using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;


namespace Camalon.Drawing
{
	/// <summary>
	/// This abstract class is the basis for all shape objects.
	/// </summary>
	[Serializable]
	[ToolboxItem( false)]
	//	[ToolboxItemFilter("Camalon.Drawing.Shapes.ShapeContainer", ToolboxItemFilterType.Require)]
    [Designer("Camalon.Drawing.Design.ShapeDesigner, Camalon.Drawing.Design", typeof(IDesigner))]
    public abstract class Shape : ContainerComponentBase
	{
		//TODOLIST----------------------------------------------------------------------	
		//TODO :Build a cone style shape
		//TODO :Build a cylindical shape 
		//TODO :Move control points to ShapeDesigner or adornment
		//TODO :Make Pen.Foregroundpen also as a shape property, that override the Pen's property

		//---------------------------------------- MEMBERS -----------------------------------------------------------

		#region Events

		#region Miscallenious Events
		[Category("Misc")]
		protected internal event ValueChangeEventHandler		ParentChanged		= null;

		#endregion Miscallenious Events


		#region Layout


		[Category("Layout")][Browsable(false)]
		public event ValueChangeEventHandler		PathBoundsChanged	= null;

		[Category("Layout")]
		public event ValueChangeEventHandler		BoundsChanged		= null;
		[Category("Layout")][Browsable(false)]
		public event ValueChangingEventHandler		BoundsChanging		= null;

		[Category("Layout")]
		public event ValueChangeEventHandler		MinSizeChanged		= null;
		[Category("Layout")][Browsable(false)]
		public event ValueChangingEventHandler		MinSizeChanging		= null;

		[Category("Layout")]
		public event ValueChangeEventHandler		AnchorChanged		= null;
		[Category("Layout")][Browsable(false)]
		public event ValueChangingEventHandler		AnchorChanging		= null;

		[Category("Layout")]
		public event EventHandler		VisibleChanged		= null;

		#endregion Layout


		#region Text

		[Category("Text")]
		public event ValueChangeEventHandler		FontChanged			= null;
		[Category("Text")][Browsable(false)]
		public event ValueChangingEventHandler		FontChanging		= null;

		[Category("Text")]
		public event ValueChangeEventHandler		TextChanged			= null;
		[Category("Text")][Browsable(false)]
		public event ValueChangingEventHandler		TextChanging		= null;

		#endregion Text

		#region Transformation

		[Category("Transformation")]
		public event ValueChangeEventHandler		WarpChanged			= null;
		[Category("Transformation")][Browsable(false)]
		public event ValueChangingEventHandler		WarpChanging		= null;
		
		[Category("Transformation")]
		public event ValueChangeEventHandler		ScaleChanged		= null;
		[Category("Transformation")][Browsable(false)]
		public event ValueChangingEventHandler		ScaleChanging		= null;

		[Category("Transformation")]
		public event ValueChangeEventHandler		RotationChanged		= null;
		[Category("Transformation")][Browsable(false)]
		public event ValueChangingEventHandler		RotationChanging	= null;

		[Category("Transformation")]
		public event ValueChangeEventHandler		ShearChanged		= null;
		[Category("Transformation")][Browsable(false)]
		public event ValueChangingEventHandler		ShearChanging		= null;

		#endregion Transformation

		#region Regions
		[Category("Combine")]
		public event ValueChangeEventHandler		JoinChanged		= null;
		[Category("Combine")][Browsable(false)]
		public event ValueChangingEventHandler		JoinChanging	= null;
		

		[Category("Combine")][Browsable(false)]
		public event EventHandler		ParentExcluded	= null;
		

		#endregion Regions

		#endregion Events

		#region Layout Members

		private				RectangleF			_bounds			= new RectangleF(0,0,200,100);

		private				Size				_minSize		= new Size(10,10);

		private				AnchorStyles		_anchor			= AnchorStyles.Top|AnchorStyles.Left;

		private bool		_suspended					= false;
		private bool		_internalSuspended			= false;

		#endregion

		#region Style Members

		private				bool	_visible			= true;

		private				FillMode _fillMode			= FillMode.Alternate;


		
		#endregion Style Members

		#region Text Members
		private bool _textOnly;

		private				string	_text				= string.Empty;
		private				Font	_font				= _DefaultFont;
		private				TextFormat _textFormat		= new TextFormat();

		#endregion Text Members

		#region Transformation Members

		private		GraphicsPath		_path			= null;
		private		GraphicsPath		_basePath		= null;
		private		GraphicsPath		_textPath		= null;
		private		GraphicsPath		_textBasePath	= null;
		private		Matrix				_matrix			= new Matrix();	

		private				int			_rotation		= 0;

		private				Shear		_shear			= Shear.Empty;

		private				Scale		_scale			= Scale.Empty;

		private				Warp		_warp			= Warp.Empty;

		private PointF		_rotationAnchor				= PointF.Empty;
		private bool		_rotationLocked				= false;
		private PointF		_rotationPointLocked		= PointF.Empty;


		private QuickWarper _parentWarper	= null;
		private QuickWarper _quickWarper	= null;


		#endregion 

		#region Region Members

		private				ShapeCombine _combine		= ShapeCombine.Empty;

		#endregion Region Members

		#region Other Members
		//		[DesignOnly(true),EditorBrowsable(EditorBrowsableState.Never)]
		//		protected internal	int	DefaultStatus	= 0;
		private				int	_status			= 0;

		private		ShapeContainer	_parent;
		internal	Shape			JoinedTo;
	
		#endregion Other Members

		//------------------------------------------------------------------------------------------------------------

		#region CONSTRUCTOR


		//		public Shape(System.ComponentModel.IContainer container):this(  )
		//		{
		//			///
		//			/// Required for Windows.Forms Class Composition Designer support
		//			///
		//			container.Add(this);
		//
		//		}

		protected Shape(  ):this(false)
		{
		
		}


		protected Shape( System.Drawing.Rectangle bounds ):this(bounds, false)
		{
		}


		protected Shape( System.Drawing.Rectangle bounds , bool textOnly ):this( textOnly )
		{
			_bounds = bounds;
		}

		protected Shape( bool textOnly )
		{
			_textOnly = textOnly;
			if( _textOnly ) _text = "Text";
			_textFormat.InternalChanged		+= new EventHandler(OnResetPath);
			
		}

		#endregion CONSTRUCTOR

		#region Dispose & Clone

		private void ClearEvents()
		{
			if( _shade != null)		_shade.InternalChanged		-= new EventHandler(OnInternalChanged);
			if( _fill != null)		_fill.InternalChanged	-= new EventHandler(OnInternalChanged);
			if( _pen != null)		_pen.InternalChanged	-= new EventHandler(OnInternalChanged);
			if( _textFill != null)	_textFill.InternalChanged	-= new EventHandler(OnInternalChanged);
			if( _textPen != null)	_textPen.InternalChanged	-= new EventHandler(OnInternalChanged);
			if( _textShade != null)	_textShade.InternalChanged	-= new EventHandler(OnInternalChanged);
			if( _textFormat != null)_textFormat.InternalChanged	-= new EventHandler(OnInternalChanged);
			if( _outline != null)	_outline.InternalChanged -= new EventHandler(OnOutlineChanged);



			//[Category("Layout")]
			Delegate.RemoveAll(PathBoundsChanged,PathBoundsChanged);	PathBoundsChanged	= null;
			Delegate.RemoveAll(BoundsChanged,BoundsChanged);		BoundsChanged		= null;
			Delegate.RemoveAll(BoundsChanging,BoundsChanging);		BoundsChanging		= null;
			Delegate.RemoveAll(MinSizeChanged,MinSizeChanged);		MinSizeChanged		= null;
			Delegate.RemoveAll(MinSizeChanging,MinSizeChanging);	MinSizeChanging		= null;
			Delegate.RemoveAll(AnchorChanged,AnchorChanged);		AnchorChanged		= null;
			Delegate.RemoveAll(AnchorChanging,AnchorChanging);		AnchorChanging		= null;
			Delegate.RemoveAll(VisibleChanged,VisibleChanged);		VisibleChanged		= null;
			//[Category("Style")]
			Delegate.RemoveAll(FontChanged,FontChanged);			FontChanged			= null;
			Delegate.RemoveAll(FontChanging,FontChanging);			FontChanging		= null;
			Delegate.RemoveAll(TextChanged,TextChanged);			TextChanged			= null;
			Delegate.RemoveAll(TextChanging,TextChanging);			TextChanging		= null;
			//[Category("Transformation")]
			Delegate.RemoveAll(WarpChanged,WarpChanged);			WarpChanged			= null;
			Delegate.RemoveAll(WarpChanging,WarpChanging);			WarpChanging		= null;
			Delegate.RemoveAll(ScaleChanged,ScaleChanged);			ScaleChanged		= null;
			Delegate.RemoveAll(ScaleChanging,ScaleChanging);		ScaleChanging		= null;
			Delegate.RemoveAll(RotationChanged,RotationChanged);	RotationChanged		= null;
			Delegate.RemoveAll(RotationChanging,RotationChanging);	RotationChanging	= null;
			Delegate.RemoveAll(ShearChanged,ShearChanged);			ShearChanged		= null;
			Delegate.RemoveAll(ShearChanging,ShearChanging);		ShearChanging		= null;
			//[Category("Region")]
			Delegate.RemoveAll(JoinChanged,JoinChanged);			JoinChanged			= null;
			Delegate.RemoveAll(JoinChanging,JoinChanging);			JoinChanging		= null;
			Delegate.RemoveAll(ParentExcluded,ParentExcluded);		ParentExcluded		= null;
		}


		protected override void Dispose( bool disposing )
		{
			this._internalSuspended = true;	

			this.ClearEvents();	

			if(_path!= null)			_path.Dispose();			_path			= null;
			if(_basePath!= null)		_basePath.Dispose();		_basePath		= null;
			if(_textPath!= null)		_textPath.Dispose();		_textPath		= null;;
			if(_textBasePath!= null)	_textBasePath.Dispose();	_textBasePath	= null;
			if(_matrix != null)			_matrix.Dispose();			_matrix			= null;	
			if(_textFormat != null )	_textFormat.Dispose();		_textFormat		= null; 

			base.Dispose( disposing);
		}

		public override object Clone()
		{
			Shape shape =  base.Clone() as Shape;

			shape.ClearEvents();

			if(_path!= null)			shape._path			= _path.Clone() as GraphicsPath;
			if(_basePath!= null)		shape._basePath		= _basePath.Clone() as GraphicsPath;
			if(_textPath!= null)		shape._textPath		= _textPath.Clone() as GraphicsPath;
			if(_textBasePath!= null)	shape._textBasePath = _textBasePath.Clone() as GraphicsPath;
			if(_matrix != null)			shape._matrix		= _matrix.Clone(); 	else shape._matrix = new Matrix();	

			return shape;
		}

		#endregion Dispose & Clone

		#region Event Handlers

		#region Misc

		protected virtual void OnParentChanged( ValueChangeEventArgs eventArg )
		{
			if( this.ParentChanged != null)
				this.ParentChanged( this, eventArg );
		}

		#endregion 

		#region Layout
        /// <summary>
        /// Raises the <see cref="E:PathBoundsChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnPathBoundsChanged(ValueChangeEventArgs eventArg)
		{
			if( PathBoundsChanged != null) 
				PathBoundsChanged( this, eventArg );

		}

        /// <summary>
        /// Raises the <see cref="E:BoundsChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnBoundsChanging( ValueChangingEventArgs eventArg )
		{
			if( eventArg.Cancel) return;

			if( this.BoundsChanging!= null)
				this.BoundsChanging( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:BoundsChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnBoundsChanged( ValueChangeEventArgs eventArg )
		{
			if( this.BoundsChanged != null)
				this.BoundsChanged( this, eventArg );
		}


        /// <summary>
        /// Raises the <see cref="E:MinSizeChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnMinSizeChanged(ValueChangeEventArgs eventArg)
		{
			if( this.MinSizeChanged != null)
				this.MinSizeChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:MinSizeChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnMinSizeChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.MinSizeChanging != null)
				this.MinSizeChanging( this, eventArg );
		}


        /// <summary>
        /// Raises the <see cref="E:AnchorChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnAnchorChanged(ValueChangeEventArgs eventArg)
		{
			if( this.AnchorChanged != null)
				this.AnchorChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:AnchorChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnAnchorChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.AnchorChanging != null)
				this.AnchorChanging( this, eventArg );
		}


		#endregion Layout

		#region Transformation
        /// <summary>
        /// Raises the <see cref="E:WarpChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnWarpChanged(ValueChangeEventArgs eventArg)
		{
			if( this.WarpChanged != null)
				this.WarpChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:WarpChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnWarpChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.WarpChanging != null)
				this.WarpChanging( this, eventArg );
		}


        /// <summary>
        /// Raises the <see cref="E:ShearChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnShearChanged(ValueChangeEventArgs eventArg)
		{
			if( this.ShearChanged != null)
				this.ShearChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:ShearChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnShearChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.ShearChanging != null)
				this.ShearChanging( this, eventArg );
		}


        /// <summary>
        /// Raises the <see cref="E:RotationChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnRotationChanged(ValueChangeEventArgs eventArg)
		{
			if( this.RotationChanged != null)
				this.RotationChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:RotationChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnRotationChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.RotationChanging != null)
				this.RotationChanging( this, eventArg );
		}


        /// <summary>
        /// Raises the <see cref="E:ScaleChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnScaleChanged(ValueChangeEventArgs eventArg)
		{
			if( this.ScaleChanged != null)
				this.ScaleChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:ScaleChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnScaleChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.ScaleChanging != null)
				this.ScaleChanging( this, eventArg );
		}

		#endregion Transformation

		#region Style
        /// <summary>
        /// Raises the <see cref="E:VisibleChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		protected virtual void OnVisibleChanged(EventArgs eventArg)
		{
			if( this.VisibleChanged != null)
				this.VisibleChanged( this, eventArg );
		}
		


		#endregion Style

		#region Text 
		protected virtual void OnFontChanged(ValueChangeEventArgs eventArg)
		{
			if( this.FontChanged != null)
				this.FontChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:FontChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnFontChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.FontChanging != null)
				this.FontChanging( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:TextChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnTextChanged(ValueChangeEventArgs eventArg)
		{
			if( this.TextChanged != null)
				this.TextChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:TextChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnTextChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.TextChanging != null)
				this.TextChanging( this, eventArg );
		}

		#endregion Text

		#region Regions

        /// <summary>
        /// Raises the <see cref="E:JoinChanged"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangeEventArgs"/> instance containing the event data.</param>
		protected virtual void OnJoinChanged(ValueChangeEventArgs eventArg)
		{
			if( this.JoinChanged!= null) this.JoinChanged( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:JoinChanging"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="Camalon.Drawing.ValueChangingEventArgs"/> instance containing the event data.</param>
		protected virtual void OnJoinChanging(ValueChangingEventArgs eventArg)
		{
			if( eventArg.Cancel) return;

			if( this.JoinChanging != null)
				this.JoinChanging( this, eventArg );
		}

        /// <summary>
        /// Raises the <see cref="E:ParentExcluded"/> event.
        /// </summary>
        /// <param name="eventArg">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		protected virtual void OnParentExcluded(EventArgs eventArg)
		{
			if( this.ParentExcluded!= null) this.ParentExcluded( this, eventArg );
		}


		#endregion Regions
		
		#endregion Event Handlers

		#region INTERNAL

		private void OnResetPath( object sender, EventArgs e)
		{ 
			ResetPath();
		}


        /// <summary>
        /// Invokes the internal changed.
        /// </summary>
        /// <param name="resetPath">if set to <c>true</c> [reset path].</param>
		protected internal void InvokeInternalChanged( bool resetPath )
		{
			if ( resetPath ) ResetPath(true);
			base.InvokeInternalChanged();
		}





        /// <summary>
        /// Gets or sets the parent.
        /// </summary>
        /// <value>The parent.</value>
		protected internal ShapeContainer Parent
		{
			get{ return _parent; }
			set
			{
				//if( value == this) throw new NotSupportedException("Shape object can not be parented to itself");
				if( _parent == value) return;

				ShapeContainer oldParent = _parent;
				_parent = value;

				this.OnParentChanged( new ValueChangeEventArgs( oldParent, _parent));
			}
		}



		//		[DesignOnly( true),EditorBrowsable(EditorBrowsableState.Never)]
		//		protected bool ShouldSerializeStatus() {	return _status != DefaultStatus;	}

		[Browsable( false )]
		[EditorBrowsable(EditorBrowsableState.Never)]
		[DefaultValue(0)]
		public virtual int Status
		{
			get
			{
				return _status;
			}
			set
			{
				if( _status == value ) return;
				_status = value;
			}
		}


		#endregion INTERNAL 

		#region HIT TEST

		internal Pen DefaultHitPen
		{
			get	{	return new Pen(Color.Empty, 5f); }
		}

//		internal Pen TextHitPen
//		{
//			get
//			{
//				
//			}
//
//		}


		private Pen HitTextPen
		{
			get
			{
				try
				{

					if( _text.Length == 0 || this.TextPen == null ) return null;
					if( this.Parent != null && this.ParentExclude  ) return null;
					if( this.JoinedTo != null) return null;

					Pen hitPen = Camalon.Drawing.Outline.GetOutlinePen( this.TextPen );
					if( hitPen == null) return this.DefaultHitPen;

					if( hitPen.Width < 3)
					{
						if( !_transformPen || _matrix.IsIdentity ) hitPen.Width =5f;
						else hitPen.Width = 3f;
					}

					if( _matrix != null && this.TransformTextPen )
						try		{	hitPen.Transform = _matrix;	} 
						catch	{	hitPen.Width = hitPen.Width;}

					return hitPen;

					
				}
				catch( Exception e)
				{
					FileWatcher.WriteLine("Shape::HitPen failed\n" + e.Message + "\n" + e.StackTrace);
					return null;
				}
			}
		}

		internal virtual Pen HitPen
		{
			get
			{
				try
				{
					//TODO: Hit pen must take the parent ResizeTransform into consideration
					if( this.JoinedTo != null ) return this.JoinedTo.HitPen;
					else if( this.ParentExclude && this.Parent != null) return this.Parent.ExcludeHitPen;
					else
					{
						Pen hitPen = Camalon.Drawing.Outline.GetOutlinePen( this.Pen );
						if( hitPen == null) return this.DefaultHitPen;

						if( hitPen.Width < 3)
						{
							if( !_transformPen || _matrix.IsIdentity ) hitPen.Width =5f;
							else hitPen.Width = 3f;
						}

						if( _matrix != null && this.TransformPen )
							try		{	hitPen.Transform = _matrix;	} 
							catch	{	hitPen.Width = hitPen.Width;}

						return hitPen;
					}
				}
				catch( Exception e)
				{
					FileWatcher.WriteLine("Shape::HitPen failed\n" + e.Message + "\n" + e.StackTrace);
					return null;
				}
			}
		}

		public PointF[] ScalingResizeTransformPoints( PointF[] points, bool invert )
		{
				
			if( this.Parent == null) return points;
			if( points == null || points.Length == 0) return points;

			using(Matrix m = this.ScalingResizeTransform( invert ))
			{
				if( m.IsIdentity) return points;

				m.TransformPoints(points);
				return points;
			}
		}

		
		public PointF ScalingResizeTransformPoint( PointF point, bool invert )
		{
			if( this.Parent == null) return point;
			using(Matrix m = this.ScalingResizeTransform( invert ))
			{
				if( m.IsIdentity) return point;

				PointF[] pts = new PointF[] { point };
				m.TransformPoints(pts);
				return pts[0];
			}
		}


		public virtual bool HitTest( PointF point)
		{
			return HitTest( point, true);
		}


		internal virtual bool HitTest( PointF point, bool invertScalingResize )
		{
			if( !this.Visible/* && !this.DesignMode*/)	return false;	

			if( invertScalingResize  && this.Parent != null) 
				//point = this.Parent.InvertScalingResize( point );
				point = this.ScalingResizeTransformPoint( point, invertScalingResize );

//			return this.HitTest( point, this.HitPen, false );

			if( this.HitTest( point, this.HitPen, false )) return true;

			return this.HitTest( point, this.HitTextPen, true );

		}

		private bool HitTest( PointF point, Pen pen, bool hitText)
		{
			if( !this.Visible /*&& !this.DesignMode*/)	return false;	

			GraphicsPath path = hitText ? this.TextPath: this.Path;
			
			if( path == null) return false;

			if( pen == null) return path.IsVisible( point );

			if(path.IsVisible( point )) return true;
			
			return path.IsOutlineVisible(point,pen);



//			if( !this.Visible /*&& !this.DesignMode*/)	return false;	
//
//			if( pen == null) return this.Path.IsVisible( point );
//
//			if(this.Path.IsVisible( point )) return true;
//			
//			return this.Path.IsOutlineVisible(point,pen);
		}

		#endregion HIT TEST
		
		#region LAYOUT


		[Browsable( false)]
		public bool Suspended
		{
			get{ return _suspended;}
		}


		public virtual void SuspendLayout()
		{
			if( _suspended) return;

			if( _path == null) ResetPath( true );
			_suspended = true;
		}


		public virtual void ResumeLayout(  )
		{

			_suspended = false;
			ResetPath(true);

		}



		public virtual Region GetRegion( bool transformScalingResize )
		{
			if( this.TextPath != null)
			{
				Region r = new Region();
				r.Exclude( this.Path );
				r.Exclude( this.TextPath );
//				using( Region textRegion = new Region( this.TextPath ))
//				{
//					textRegion.Translate( -0.3f,-0.3f );
//					r.Exclude( textRegion);// this.TextPath );
//				}

				using( Region r1= new Region())  r.Complement( r1 );

				if( transformScalingResize )
					using( Matrix m = this.ScalingResizeTransform( false ))
						if( !m.IsIdentity) r.Transform(  m );

				return r;
			}
			else
			{
				Region r = new Region( this.Path );

				if( transformScalingResize )
					using( Matrix m = this.ScalingResizeTransform( false ))
						if( !m.IsIdentity) r.Transform(  m );
			
				return r;
			}

		}


		public virtual Matrix ScalingResizeTransform( bool invert )
		{
		
				if( this.Parent == null) return new Matrix();
				
				ShapeContainer parent = this.Parent;
				Matrix m = this.Parent.ResizeTransform;
 
				while( parent.Parent != null)
					using( Matrix m2 = parent.Parent.ResizeTransform )
					{
						if( m != null) m.Multiply( m2, MatrixOrder.Append );	
						parent = parent.Parent;
					}

				if(invert && !m.IsIdentity  ) m.Invert();

				return m;
		
		}

		private RectangleF RecalculateInvalidatingBounds()
		{
			RectangleF ib = RectangleF.Empty;//Shape bounds
			RectangleF sb = RectangleF.Empty;//Shade bounds
			bool needsShadingInvalidate = false;
			Point offset= Point.Empty;//Shade offset values

			Shape joinedTo = null;
			if( this.JoinedTo != null) joinedTo = this.JoinedTo;
			else if( this.Parent != null && this.ParentExclude) joinedTo = _parent;

			if( joinedTo == null)	
			{
				needsShadingInvalidate = this.Shade != null && (this.Shade.Pen != null || this.Shade.Fill != null);
				if( needsShadingInvalidate ) 
				{
					offset = this.Shade.Offset;
					offset.X *=this.Shade.Repeat;
					offset.Y *=this.Shade.Repeat;
 				}
			}
			else 
			{
				needsShadingInvalidate = joinedTo.Shade != null && (joinedTo.Shade.Pen != null || joinedTo.Shade.Fill != null);
				if( needsShadingInvalidate ) 
				{
					offset = joinedTo.Shade.Offset;
					offset.X *=joinedTo.Shade.Repeat;
					offset.Y *=joinedTo.Shade.Repeat;
				}
			}

			if( this.Parent == null)
			{
					
				if( ! needsShadingInvalidate) return this.GetPathBounds();
				else
				{
					sb = ib;
					sb.X+= offset.X;
					sb.Y+= offset.Y;
					return RectangleF.Union( ib, sb );;
				}
			}
				
			ShapeContainer parent = this.Parent;
			using(Matrix m = this.ScalingResizeTransform( false ))
			{
					
				Pen hitPen = null;
				Pen shadeHitPen = null;
				//Check pen available
				ShapePen pen = joinedTo == null ? _pen: joinedTo.Pen;
					
				//Check shade pen available
				ShapePen shadePen = null;
				if( needsShadingInvalidate ) 
				{
					if( joinedTo == null) shadePen = this.Shade.Pen;
					else shadePen = joinedTo.Shade.Pen;
				}

				
				if( pen != null  ) 
				{
					//if( _pen.StartCap.Style != CapStyle.None || _pen.EndCap.Style != CapStyle.None )
					hitPen = Camalon.Drawing.Outline.GetOutlinePen( pen );
					//TODO :Check if transform pen needed here
					//if( hitPen!= null && !m.IsIdentity) hitPen.Transform = m;
				}

				if( shadePen != null)
					shadeHitPen = Camalon.Drawing.Outline.GetOutlinePen( shadePen );

				using( hitPen )
				using(shadeHitPen)
				{
			
					ib =  this.GetPathBounds( m , hitPen );
					sb = ib;
						
					if( needsShadingInvalidate)
					{
						sb = this.GetPathBounds( m, shadeHitPen);
						sb.X+= offset.X;
						sb.Y+= offset.Y;
					}

					//This shape is joined to another shape
					if( joinedTo != null) 
					{
						if( !needsShadingInvalidate)
							return RectangleF.Union( ib, joinedTo.GetPathBounds(m, hitPen));
						else
						{
							ib =  RectangleF.Union( ib, joinedTo.GetPathBounds(m, hitPen));
							RectangleF jtb = joinedTo.GetPathBounds(m, shadeHitPen);
							jtb.X+= offset.X;
							jtb.Y+= offset.Y;
							sb = RectangleF.Union( sb, jtb);
								
							return RectangleF.Union( ib, sb);
						}
					}
					//Has no joins
					if( _combine.Shape == null) 
					{
						if(! needsShadingInvalidate) return ib;
						else return RectangleF.Union( ib, sb);
					}

					//Has a join but other than parent
					if(_combine.Shape != this.Parent ) 
					{
						if( !needsShadingInvalidate) return RectangleF.Union( ib, _combine.Shape.GetPathBounds(m, hitPen));
						else
						{
							ib = RectangleF.Union( ib, _combine.Shape.GetPathBounds(m, hitPen));
							RectangleF jtb = _combine.Shape.GetPathBounds(m, shadeHitPen);
							jtb.X+= offset.X;
							jtb.Y+= offset.Y;
							sb = RectangleF.Union( sb, jtb);
								
							return RectangleF.Union( ib, sb);

						}
					}


					if( !needsShadingInvalidate) return ib;
					else return RectangleF.Union( ib, sb );;
				}
			}

		}

		[Browsable( false )]
		public virtual RectangleF InvalidatingBounds
		{
			get
			{
				return RecalculateInvalidatingBounds();
			}
		}



		[Browsable(true)]
		[Category("Layout")]
		[DefaultValue(AnchorStyles.Top|AnchorStyles.Left)]
		public virtual AnchorStyles Anchor
		{
			get
			{
				if( this.Parent != null && this.Parent.ShouldScaleOnResize)// && this.Parent.ScalingResize) 
					return AnchorStyles.Top|AnchorStyles.Left;
			
				return _anchor;
			}
			set
			{ 
				if( !_canAnchor) return;

				if( value == _anchor) return;

				AnchorStyles oldValue= _anchor;
				ValueChangingEventArgs e = new ValueChangingEventArgs( _anchor, value);
				OnAnchorChanging( e );
				if( e.Cancel) return;

				_anchor = value;

				OnAnchorChanged(new ValueChangeEventArgs( oldValue, value));
			}
		}



		[Browsable(true)]
		[Category("Layout")]
		[DefaultValue(typeof(Size),"10,10")]
		public virtual Size MinSize
		{
			get{ return _minSize ;}
			set
			{ 
				if( value == _minSize) return;

				Size oldValue = _minSize;

				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
				try	{		_internalSuspended = true;	OnMinSizeChanging(e);	}
				finally	{	_internalSuspended = false;	}
				if( e.Cancel ) return;


				_minSize = value;
				InvokeInternalChanged(true);

				OnMinSizeChanged( new ValueChangeEventArgs(oldValue, value ) );

			}
		}



		[Browsable(true)]
		[Category("Layout")]
			//		[DefaultValue(typeof(Size),"200,100")]
		public Size Size
		{
			get{ return Size.Round (_bounds.Size );}
			set
			{ 
				try
				{
					if( !_canResize) return;

					if( value == _bounds.Size) return;

					RectangleF bounds = _bounds;
					bounds.Size= value;
					this.Bounds = bounds;
				}
				catch( Exception ex)
				{
					FileWatcher.WriteLine( ex.StackTrace);
				}

			}
		}

		
		[Browsable(true)]
		[Category("Layout")]
			//		[DefaultValue(typeof(Point),"0,0")]
		public Point Position
		{
			get { 	return Point.Round( _bounds.Location );		}
			set
			{ 
				try
				{
					if( value == _bounds.Location) return;

					RectangleF bounds = _bounds;
					bounds.Location = value;
					this.Bounds = bounds;
				}
				catch( Exception ex)
				{
					FileWatcher.WriteLine( ex.StackTrace);
				}

			}
		}

		protected internal virtual void SetBounds( RectangleF bounds , bool fireBoundsChangedEvent)
		{
//			if( bounds.Width  < _minSize.Width  ) bounds.Width  = _minSize.Width;
//			if( bounds.Height < _minSize.Height ) bounds.Height = _minSize.Height;

			if( _bounds == bounds ) return;

			RectangleF oldBounds = _bounds;


			_bounds = bounds;

			if( fireBoundsChangedEvent)
				OnBoundsChanged(new ValueChangeEventArgs( oldBounds, bounds ));
		}

		[Browsable(false)]
		[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden)]
		public virtual RectangleF Bounds
		{
			get
			{ 
				return _bounds ;
			}
			set
			{ 
				if( !_canResize ) value.Size = _bounds.Size;

				if( value.Width  < _minSize.Width  ) value.Width  = _minSize.Width;
				if( value.Height < _minSize.Height ) value.Height = _minSize.Height;

				if( _bounds == value) return;
				
			
				RectangleF oldValue = _bounds;			
				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );

				try	{		_internalSuspended = true;		OnBoundsChanging(e);	}
				finally	{	_internalSuspended = false;		}
				if( e.Cancel ) return;
	
				_bounds = value;

				OnBoundsChanged( new ValueChangeEventArgs(oldValue, value) );
				ResetPath();//CAUTION: Call this after the OnBoundsChanged... That means, keep it here

			}
		}


		#endregion LAYOUT

		#region STYLE

		[Category("Style")]
		[DefaultValue(true)]
		public bool Visible
		{
			get{ return _visible;}
			set
			{
				try
				{
					if(_visible == value) return;

					_visible = value;

					InvokeInternalChanged(false);
					OnVisibleChanged( new EventArgs( ));

				}
				catch( Exception e)
				{
					FileWatcher.WriteLine("Shape::Visible failed"+ e.Message);
				}

			}
		}



		[Category("Style")]
		[DefaultValue(FillMode.Alternate)]
		public FillMode FillMode
		{
			get{ return _fillMode;}
			set
			{ 
				if( _fillMode == value) return;

				_fillMode = value;
				
				if( _path != null) _path.FillMode = _fillMode;
				
				InvokeInternalChanged(false);
			}
		}


		#endregion STYLE
		
		#region TEXT



		[Category("Text"), RefreshProperties(RefreshProperties.Repaint)]
		[DefaultValue("")]
        [Editor("Camalon.Drawing.Design.MultiLineTextEditor, Camalon.Drawing.Design", typeof(UITypeEditor))]
		public string Text
		{
			get{ return _text;}
			set
			{
				if( _textOnly )
				{
					if( value == null || value.Length == 0) _text = "Text";
				}
				
					
				if( _text == value ) return;


				string oldValue = _text;
				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
				try	{		_internalSuspended = true;	OnTextChanging(e);	}
				finally	{	_internalSuspended = false;		}
				if( e.Cancel ) return;

				_text = value;

				ResetPath();
				OnTextChanged( new ValueChangeEventArgs(oldValue, value ));
			}
		}


		[DesignOnly( true), EditorBrowsable(EditorBrowsableState.Never)]
		protected virtual bool ShouldSerializeTextFormat()
		{ 
			return !_textFormat.IsDefault();
		}

		//[DesignOnly( true), EditorBrowsable(EditorBrowsableState.Never)]
		protected void ResetTextFormat()
		{
			_textFormat.Reset();
		}

		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		[Category("Text")]
		public TextFormat TextFormat
		{
			get
			{
				return _textFormat;
			}
		}


		private static Font _DefaultFont
		{
			get
			{
				return new System.Drawing.Font("Tahoma", 72F);
			}

		}


		//		private bool ShouldSerializeFont()
		//		{
		//			if( _parent != null && _parent.Font != null) return _font != _parent.Font;
		//			else return true;
		//		}
		//		
		//		private void ResetFont()
		//		{
		//			if( _parent != null && _parent.Font != null) _font = _parent.Font;
		//			else _font = _DefaultFont;
		//		}

		[Category("Text")]
		[RefreshProperties(RefreshProperties.Repaint)]
		[AmbientValue(null)]
		[DefaultValue(typeof(Font),"Tahoma,72pt")]
		public virtual Font Font
		{
			get
			{ 
				return _font;
			}
			set
			{ 

				if (value == null) value = _DefaultFont;

				if( _font == value ) return;

				Font oldValue = _font;			

				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
				try	{		_internalSuspended = true;		OnFontChanging(e);	}
				finally	{	_internalSuspended = false;		}
				if( e.Cancel ) return;

				_font = value;

				if( value != null) InvokeInternalChanged( true );

				OnFontChanged( new ValueChangeEventArgs(oldValue, value ) );

			}
		}

 
		#endregion TEXT

		#region PATH
		public GraphicsPath CloneBasePath()
		{
			return BasePath.Clone() as GraphicsPath;
		}

		public GraphicsPath ClonePath()
		{
			return Path.Clone() as GraphicsPath;
		}

		protected internal GraphicsPath BasePath
		{
			get
			{
				if( _path == null)	ResetPath();
				return _basePath;
			}
		}

		public GraphicsPath CloneTextPath()
		{
			if( _textOnly ) return null;

			GraphicsPath path = TextPath;
			if( path == null) return null;
			else return path.Clone() as GraphicsPath;
		}

		public GraphicsPath CloneBaseTextPath()
		{
			if( _textOnly ) return null;

			GraphicsPath path = this.BaseTextPath;
			if( path == null) return null;
			else return path.Clone() as GraphicsPath;
		}

		protected internal GraphicsPath BaseTextPath
		{
			get
			{
				if( _textOnly ) return null;

				if( _path == null)	ResetPath();
				return _textBasePath;
			}
		}

		protected internal GraphicsPath TextPath
		{
			get
			{
				if( _textOnly ) return null;

				if( _path == null) ResetPath();
				return _textPath;
			}
		}

		
		protected abstract GraphicsPath MakePath(RectangleF bounds);
		protected internal GraphicsPath Path
		{
			get
			{
				if( _path == null) ResetPath(true);

				return _path;
			}
		}
		#endregion PATH

		#region TRANSFORMATION

		#region Can Transform
		private bool _canRotate	= true;
		private bool _canWarp	= true;
		private bool _canScale	= true;
		private	bool _canShear	= true;
		private bool _canResize	= true;
		private bool _canWarpInternal	= true;
		private bool _canScaleInternal	= true;
		private	bool _canShearInternal	= true;
		private	bool _canOutline	= true;
		private bool _canAnchor		= true;

		protected internal void SetCanAnchor( bool canAnchor)//, AnchorStyles defaultAnchor )
		{
			if( !canAnchor ) 
			{
				_anchor = AnchorStyles.Top|AnchorStyles.Left;//defaultAnchor;
			}
			_canAnchor = canAnchor; 		
		}

		[Browsable(false)]
		public bool CanAnchor
		{	get	{	return _canAnchor;	}	}


		protected internal void SetCanOutline( bool canOutline )
		{
			if( !canOutline ) _outline = null;
			_canOutline = canOutline; 		
		}

		[Browsable(false)]
		public bool CanOutline
		{	get	{	return _canOutline;	}	}


		protected internal void SetCanWarp( bool canWarp )
		{
			if( !canWarp ) _warp = Warp.Empty;
			_canWarp = canWarp; 		
		}

		[Browsable(false)]
		public bool CanWarp
		{	get	{	return _canWarp && _canWarpInternal;	}	}

		protected internal void SetCanScale( bool canScale )
		{
			if( !canScale ) _scale = Scale.Empty;
			_canScale = canScale; 		
		}

		[Browsable(false)]
		public bool CanScale
		{	get	{	return _canScale && _canScaleInternal;	}	}

		protected internal void SetCanShear( bool canShear )
		{	
			if( !canShear ) _shear = Shear.Empty;
			_canShear = canShear; 		
		}

		[Browsable(false)]
		public bool CanShear
		{	get	{	return _canShear && _canShearInternal;	}	}

		protected internal void SetCanResize( bool canResize )
		{
		
			_canResize = canResize; 		
		}

		[Browsable(false)]
		public bool CanResize
		{	get	{	return _canResize  ;	}	}

		protected internal void SetCanRotate( bool canRotate )
		{
			if( !canRotate ) _rotation = 0;
			_canRotate = canRotate; 		
		}

		[Browsable(false)]
		public bool CanRotate
		{	get	{	return _canRotate;	}	}
		#endregion Can Transform


		public virtual void ResetTransform( )
		{
			bool alreadySuspended = _suspended;

			try
			{
				if( !alreadySuspended ) SuspendLayout();
				this.Warp			= Warp.Empty;
				this.Scale			= Scale.Empty;
				this.Rotation		= 0;
				this.Shear			= Shear.Empty;
			}
			finally
			{
				if(!alreadySuspended) 	ResumeLayout();
			}
		}


		public GraphicsPath GetRotatingPath()
		{
			if( !_warp.IsEmpty)
			{
				Matrix m = new Matrix();

				RectangleF pbs = this.BasePath.GetBounds();
				PointF center = RectangleUtil.CenterPoint(pbs);
				PointF[] pts = _warp.GetPoints( pbs );
				GraphicsPath path = new GraphicsPath();
				path.AddPolygon(pts);

				center = RectangleUtil.CenterPoint( path.GetBounds() );
			
				if( _rotation != 0 )
					m.RotateAt(_rotation, GetRotatingPoint(), MatrixOrder.Append);

				if( !m.IsIdentity ) 
				{
					path.Transform( m );
					pts = path.PathPoints;
				}
				m.Dispose(); m = null;

				path = CloneBasePath();
				QuickWarper qWarper= new QuickWarper(pts, _basePath.GetBounds(),_warp.WarpMode);
				path = qWarper.WarpPath( path );

				return path;

			}
			else
			{
				GraphicsPath path = this.CloneBasePath();
				Matrix m = new Matrix();
				PointF center = RectangleUtil.CenterPoint(path.GetBounds());
				
				if( _rotation != 0 )
					m.RotateAt(_rotation, GetRotatingPoint(), MatrixOrder.Append);

				if( !m.IsIdentity ) path.Transform( m );
				
				m.Dispose(); m = null;

				return path;


			}
		}

		public GraphicsPath GetShearingPath()
		{
			if( !_warp.IsEmpty)
			{
				Matrix m = new Matrix();

				RectangleF pbs = this.BasePath.GetBounds();
				PointF center = RectangleUtil.CenterPoint(pbs);
				PointF[] pts = _warp.GetPoints( pbs );
				GraphicsPath path = new GraphicsPath();
				path.AddPolygon(pts);

				center = RectangleUtil.CenterPoint( path.GetBounds() );
			
				if( _rotation != 0 )
					m.RotateAt(_rotation, GetRotatingPoint(), MatrixOrder.Append);

			
				if( !_shear.IsEmpty )
				{
					RectangleF shearingBounds = path.GetBounds();
					if( _shear.AppendRotate) shearingBounds = path.GetBounds(m);

					float shearX = 0f;
					float shearY = 0f;
					if( _shear.X != 0) shearX = _shear.X / ( shearingBounds.Height/2f);
					if( _shear.Y != 0) shearY = _shear.Y / ( shearingBounds.Width/2f);


					center = RectangleUtil.CenterPoint( path.GetBounds(m) );
					MatrixOrder order = _shear.AppendRotate ? MatrixOrder.Append : MatrixOrder.Prepend;
					m.Shear( shearX,shearY, order);

					PointF p2 = RectangleUtil.CenterPoint( path.GetBounds(m));
					float px = center.X - p2.X;
					float py = center.Y - p2.Y;
					m.Translate( px,py,MatrixOrder.Append );

				}

				if( !m.IsIdentity ) 
				{
					path.Transform( m );
					pts = path.PathPoints;
				}
				m.Dispose(); m = null;

				path = CloneBasePath();
				QuickWarper qWarper= new QuickWarper(pts, _basePath.GetBounds(),_warp.WarpMode);
				path = qWarper.WarpPath( path );

				return path;

			}
			else
			{
				GraphicsPath path = this.CloneBasePath();
				Matrix m = new Matrix();
				PointF center = RectangleUtil.CenterPoint(path.GetBounds());
				
				if( _rotation != 0 )
					m.RotateAt(_rotation, GetRotatingPoint(), MatrixOrder.Append);

				if( !_shear.IsEmpty )
				{
					RectangleF shearingBounds = path.GetBounds();
					if( _shear.AppendRotate) shearingBounds = path.GetBounds(m);

					float shearX = 0f;
					float shearY = 0f;
					if( _shear.X != 0) shearX = _shear.X / ( shearingBounds.Height / 2f );
					if( _shear.Y != 0) shearY = _shear.Y / ( shearingBounds.Width  / 2f );

					center = RectangleUtil.CenterPoint(path.GetBounds(m));
					MatrixOrder order = _shear.AppendRotate ? MatrixOrder.Append : MatrixOrder.Prepend;
					m.Shear( shearX,shearY, order);

					PointF p2 = RectangleUtil.CenterPoint( path.GetBounds(m));
					float px = center.X - p2.X;
					float py = center.Y - p2.Y;
					m.Translate( px,py, MatrixOrder.Append );
				}

				if( !m.IsIdentity ) path.Transform( m );
				
				m.Dispose(); m = null;

				return path;

			}

		}


		#region Reset Path

	
		public void ResetPath(/*Remakes base path*/)
		{
			ResetPath( true );
			
		}

		//This internal properties used only by Shape container( If this object is a Shape container)
		// Simple shapes will have tthese values always null...
		internal bool IsContainerBaseShape = false;


//		private Matrix _globalTransform;
//		internal Matrix GlobalTransform//Only used if this object is a ShapeContainer
//		{//Only used if this object is a ShapeContainer
//			get{ return _globalTransform;}
//			set
//			{
//				if( _globalTransform != null) _globalTransform.Dispose();
//				_globalTransform = value;
//			}
//
//		}
		public virtual void ResetPath( bool remakeBasePath )
		{
			if( _suspended || _internalSuspended  ) return;

		
			RectangleF oldBounds	= RectangleF.Empty;

			try
			{
				if( _path != null) oldBounds = _path.GetBounds();

				//Reset Matrix-----------------------------------------------
				if( _matrix == null) _matrix = new Matrix();//Identity Matrix;
				else _matrix.Reset();//Reset the Matrix

				_quickWarper = null;
				
				bool canTransformText = true;


				if( remakeBasePath || _basePath == null)
				{
					if( _basePath != null) {_basePath.Dispose(); _basePath = null; }
					if( _textBasePath != null) {_textBasePath.Dispose(); _textBasePath= null; }

					
					if( _textOnly ) 
					{
						_basePath = MakeTextPath( _bounds );

						if( _basePath == null) 
						{
							_basePath = new GraphicsPath();
							_basePath.AddRectangle( _bounds);
							canTransformText = false;

						}
					}
					else _basePath = MakePath( _bounds );

					//TODO :Make an exception Path, if returns null
					if( _basePath == null) return;

					RectangleF b = _basePath.GetBounds();
					if( b.Width == 0 && b.Height==0) return;


//					if( this.GlobalTransform != null && !this.GlobalTransform.IsIdentity)
//						_basePath.Transform( GlobalTransform );


					
					
					if(!canTransformText ||( ( b.Height == 0 || b.Width==0 ) && _outline == null) ) 
					{
						_canShearInternal	= false;//	_rotation != 0 && _shear.AppendRotate ;
						_canScaleInternal	= false;//	(_canShearInternal && !_shear.IsEmpty ) || ( _rotation != 0 && _scale.AppendRotate );
						_canWarpInternal	= false;
					}
					else
					{
						_canShearInternal	= true;//	_rotation != 0 && _shear.AppendRotate ;
						_canScaleInternal	= true;//	(_canShearInternal && !_shear.IsEmpty ) || ( _rotation != 0 && _scale.AppendRotate );
						_canWarpInternal	= true;
					}

					_basePath.FillMode = _fillMode;
					
					if( _canOutline && _outline != null && _outline.Transform)
						using(Pen pen = _outline.Pen)
							if(pen != null) _basePath.Widen( pen , null, _outline.Flatness);

					#region MAKE TEXT PATH
					if( !_textOnly  && !this.IsContainerBaseShape) 
					{
						_textBasePath = MakeTextPath( b );
						
//						if( _textBasePath != null && this.GlobalTransform != null && !this.GlobalTransform.IsIdentity)
//						_textBasePath.Transform( this.GlobalTransform );


					}
					#endregion MAKE TEXT PATH

				}
				


				if( _path != null) {_path.Dispose();_path= null;}
				_path = _basePath.Clone() as GraphicsPath;

				

				if( _textPath != null) {_textPath.Dispose();_textPath= null;}
				if( _textBasePath != null) _textPath = _textBasePath.Clone() as GraphicsPath;



				if(CanWarp && !_warp.IsEmpty) 
					TransformWarpPath(_textFormat != null && _textFormat.Transform );
				else	
					TransformPath( _textFormat != null && _textFormat.Transform );


				if( this.ParentWarper != null )
				{
					_path = this.ParentWarper.WarpPath( _path );
					if( _textPath != null) _textPath = this.ParentWarper.WarpPath( _textPath ); 
				}


				if( _canOutline && _outline != null && !_outline.Transform)
					using(Pen pen = _outline.Pen)
						if(pen != null) _path.Widen( pen , null, _outline.Flatness);



				OnPathBoundsChanged(new ValueChangeEventArgs(oldBounds, _path.GetBounds()));


			}
			catch( Exception e)
			{
				
				FileWatcher.WriteLine( "---Object: " + TypeDescriptor.GetComponentName( this));
				FileWatcher.WriteLine( "---Object Type: " + this.GetType().Name);
				FileWatcher.WriteLine( "ResetPath Exception:" + e.StackTrace);
				FileWatcher.WriteLine( "Message:" + e.Message + ", Source:" + e.Source);
				if( e.InnerException != null) 
					FileWatcher.WriteLine( "ResetPath Inner Exception:" + e.InnerException.StackTrace);
				return;
			}


		}



		protected virtual GraphicsPath MakeTextPath( RectangleF baseBounds )
		{
			string text = _text;
			Font font   = _font;
 
			if( text.Length == 0 || 
				font == null || 
				baseBounds.Height <= 0 || 
				baseBounds.Width <= 0 ) return null;


			try
			{
				GraphicsPath txtPath	= new GraphicsPath();
				StringFormat sf			= null;

				if( _textFormat.Typographic ) sf = StringFormat.GenericTypographic.Clone() as StringFormat ;
				else sf = StringFormat.GenericDefault.Clone() as StringFormat;
				sf.FormatFlags		= _textFormat.FormatFlags|StringFormatFlags.LineLimit;
				//sf.FormatFlags		^= StringFormatFlags.NoClip|StringFormatFlags.FitBlackBox;
					
				sf.LineAlignment	= _textFormat.LineAlignment;
				sf.Alignment		= _textFormat.TextAlignment;
				sf.Trimming			= _textFormat.Trimming == StringTrimming.None ? StringTrimming.Character:_textFormat.Trimming;

				
				// Some text type go outside of the box and we do not want this.
				// To get the text in the bounds by the first try, make the text 
				// area a little smaller than the actual bounds to be drawn. 
				// Because of this we use some offset values so that the most 
				// of the text types can be drawn in the given area. 
					
				RectangleF bItalic = baseBounds;
				bItalic.Inflate(-3,-3);//Set an offset of -3px for all type of text

				float italicOffset = 7f; //Ofsset for italic fnt types
				if( font.Italic )
				{ //If the font is italic, it is sure that the text is going to outside of the base path.
					// Because of this we making the drawing rect a little bit.	
					if ( _textFormat.TextDirection != TextDirection.Horizontal)  bItalic.Height-= italicOffset;//Vertical
					else { bItalic.Width -= italicOffset;	}//Horizontal
				}

				
				txtPath.AddString( text,font.FontFamily, (int)font.Style,font.Size, bItalic, sf );

				RectangleF txtBounds	= txtPath.GetBounds();
				bool badBounds = (baseBounds != txtBounds) && (!baseBounds.Contains( txtBounds ));
				italicOffset = 5f;//Successive Approximation 
				
				//Bounds still not ok(bigger)? Then we try to make another text 
				//path in a smaller rectangle area than the last one.	
				while( badBounds && txtBounds.Width > 0 && txtBounds.Height >0) 
				{
					if ( _textFormat.TextDirection != TextDirection.Horizontal)  bItalic.Height-= italicOffset;//Vertical
					else { bItalic.Width -= italicOffset;	}//Horizontal

					txtPath.Reset();

					txtPath.AddString( text,font.FontFamily, (int)font.Style,font.Size, bItalic, sf );
					txtBounds	= txtPath.GetBounds();
						
					badBounds = (baseBounds != txtBounds) && (!baseBounds.Contains( txtBounds ));
				}
					

				// Still bad...Then give up...!
				if( badBounds ) {txtPath.Dispose(); txtPath= null; return null; }

				if( _textFormat.TextDirection  == TextDirection.VerticalBottomToTop)
				{	//Flip XY
					Matrix m = new Matrix();
					m.Scale(-1,-1,MatrixOrder.Append);//Flip XY
					RectangleF tb = txtPath.GetBounds(m);
					m.Translate( txtBounds.X - tb.X, txtBounds.Y - tb.Y, MatrixOrder.Append);
					txtPath.Transform(m);
					m.Dispose();m = null;
				}

				return txtPath;
			}
			catch( Exception e)
			{
				FileWatcher.WriteLine( "Shape::MakeTextPath failed:"+ e.Message );
				return null;
			}

		}

		private PointF[] TransformWarpPoints( RectangleF warpingBase )
		{
			try
			{
				if( _warp.IsEmpty) return null;

					
				Matrix m = new Matrix();	

				RectangleF pbs = warpingBase;
				PointF center = RectangleUtil.CenterPoint(pbs);
				PointF[] pts = _warp.GetPoints( pbs );
				GraphicsPath path = new GraphicsPath();
				path.AddPolygon(pts);

				center = RectangleUtil.CenterPoint( path.GetBounds() );
			
				if(CanRotate && _rotation != 0 )
					m.RotateAt(_rotation, GetRotatingPoint(), MatrixOrder.Append);

			
				if(CanShear && !_shear.IsEmpty )
				{
					RectangleF shearingBounds = path.GetBounds();
					if( _shear.AppendRotate) shearingBounds = path.GetBounds(m);

					float shearX = 0f;
					float shearY = 0f;
					if( _shear.X != 0) shearX = _shear.X / ( shearingBounds.Height/2f);
					if( _shear.Y != 0) shearY = _shear.Y / ( shearingBounds.Width/2f);


					center = RectangleUtil.CenterPoint( path.GetBounds(m) );
					MatrixOrder order = _shear.AppendRotate ? MatrixOrder.Append : MatrixOrder.Prepend;
					m.Shear( shearX,shearY, order);

					PointF p2 = RectangleUtil.CenterPoint( path.GetBounds(m));
					float px = center.X - p2.X;
					float py = center.Y - p2.Y;
					m.Translate( px,py,MatrixOrder.Append );

				}


				_matrix = m.Clone();

				if(CanScale && !_scale.IsEmpty)
				{
					MatrixOrder scalingOrder = _scale.AppendRotate ? MatrixOrder.Append: MatrixOrder.Prepend;

					if( scalingOrder == MatrixOrder.Append )
					{
						path.Transform(m);
						m= new Matrix();
						pts = path.PathPoints;
						path.Reset();
						path.AddPolygon( pts);
					}

					RectangleF pbm = path.GetBounds( m );
					center = RectangleUtil.CenterPoint( pbm );

					if( scalingOrder == MatrixOrder.Prepend ) pbm = path.GetBounds();

					float scaleX = 1+ ((2f*_scale.X) /pbm.Width);
					float scaleY = 1+ ((2f*_scale.Y) /pbm.Height);
					m.Scale( scaleX, scaleY, scalingOrder);

					PointF p21 = RectangleUtil.CenterPoint(path.GetBounds(m ));
					float px1 = (center.X - p21.X);
					float py1 = (center.Y - p21.Y);
					m.Translate( px1,py1, MatrixOrder.Append );

					if( scalingOrder == MatrixOrder.Append ) _matrix.Multiply( m , MatrixOrder.Append);
					else _matrix = m;
					
				}

				if( !m.IsIdentity ) 
				{
					path.Transform( m );
					pts = path.PathPoints;
				}

				path.Dispose();

				return pts;
			}
			catch(Exception e)
			{
				FileWatcher.WriteLine("Shape::TransformWarpPoints failed" + e.Message );
				return null;
			}

		}
		
		private bool TransformWarpPath(bool transformText)
		{
			return this.TransformWarpPath( transformText, _basePath.GetBounds());
		}


		protected bool TransformWarpPath(bool transformText, RectangleF warpingBase)
		{

			try
			{
				if( !CanWarp) return false;

				RectangleF pbs = warpingBase;
				PointF[] pts = this.TransformWarpPoints(pbs);
				if( pts == null) return false;

				_quickWarper= new QuickWarper(pts,pbs,_warp.WarpMode);

				_path = _quickWarper.WarpPath( _path );
				if( transformText && _textPath != null) _textPath = _quickWarper.WarpPath( _textPath );
				
					
				return true;
			}
			catch (Exception e)
			{
				FileWatcher.WriteLine("Shape::ResetWarpTransform failed" + e.Message );
				return false;
			}
		}

		private void TransformPath(bool transformText)
		{
			try
			{
				RectangleF b = _path.GetBounds();
				PointF center = RectangleUtil.CenterPoint(b);
				
				if(CanRotate && _rotation != 0 )
					_matrix.RotateAt(_rotation, GetRotatingPoint(), MatrixOrder.Append);


				if(CanShear && !_shear.IsEmpty )
				{
					RectangleF shearingBounds = _path.GetBounds();
					if( _shear.AppendRotate) shearingBounds = _path.GetBounds(_matrix);
					
					

					float shearX = 0f;
					float shearY = 0f;
					if( _shear.X != 0) shearX = _shear.X / ( shearingBounds.Height/2f);
					if( _shear.Y != 0) shearY = _shear.Y / ( shearingBounds.Width/2f);

					center = RectangleUtil.CenterPoint(_path.GetBounds(_matrix));
					MatrixOrder order = _shear.AppendRotate ? MatrixOrder.Append : MatrixOrder.Prepend;
					_matrix.Shear( shearX,shearY, order);

					PointF p2 = RectangleUtil.CenterPoint( _path.GetBounds(_matrix));
					float px = center.X - p2.X;
					float py = center.Y - p2.Y;
					_matrix.Translate( px,py, MatrixOrder.Append );
				}

				if(CanScale && !_scale.IsEmpty)
				{
					MatrixOrder scalingOrder = _scale.AppendRotate ? MatrixOrder.Append: MatrixOrder.Prepend;
					RectangleF pbm = _path.GetBounds( _matrix );
					center = RectangleUtil.CenterPoint(pbm );
					if( scalingOrder == MatrixOrder.Prepend ) pbm = _path.GetBounds();
				
					float scaleX = 1+ ((2*_scale.X) /pbm.Width);
					float scaleY = 1+ ((2*_scale.Y) /pbm.Height);
					_matrix.Scale( scaleX, scaleY, scalingOrder);

					PointF p2 = RectangleUtil.CenterPoint(_path.GetBounds(_matrix ));
					float px = (center.X - p2.X);
					float py = (center.Y - p2.Y);
					_matrix.Translate( px,py, MatrixOrder.Append );

				}

				if( !_matrix.IsIdentity ) 
				{
					_path.Transform( _matrix );
					if( _textPath != null ) _textPath.Transform( _matrix );

				}

			}
			catch( Exception e)
			{
				FileWatcher.WriteLine( "ResetTransform Exception:" + e.Message );
			}

		}



		#endregion Reset Path

		#region Rotation/Angle Methods
		public PointF LockRotation()
		{

			_rotationLocked = false;
			_rotationPointLocked = GetRotatingPoint();
			_rotationLocked = true;

			return _rotationPointLocked;
		}

		public void UnlockRotation(  )
		{
			UnlockRotation( true);
		}

		public void UnlockRotation( bool moveToCenter )
		{
			_rotationLocked = false;

			if( !moveToCenter) return;

			PointF	oc	= RectangleUtil.CenterPoint(_path.GetBounds());
			ResetPath(false);
			PointF	cc	= RectangleUtil.CenterPoint( _path.GetBounds());

			if( oc != cc)
			{
				RectangleF oldValue = _bounds;
				PointF dxy = new PointF( oc.X - cc.X, oc.Y - cc.Y);
				PointF pos = _bounds.Location;
				pos.X += dxy.X;
				pos.Y += dxy.Y;
				this.Bounds = new RectangleF( pos, oldValue.Size);
			}
		}
	
		public int GetRotatingAngle( Point rotatingPoint )
		{
			return (int)Math.Round(  GetAngle( rotatingPoint, GetRotatingPoint()));
		}

		private double GetAngle( PointF rotatingPoint, PointF anchorPoint )
		{
			//Recalculate radius
			//------------------------------------------------
			PointF pt = new PointF (rotatingPoint.X - anchorPoint.X , rotatingPoint.Y  - anchorPoint.Y  ); 
			double radian = Math.Atan2( pt.X, pt.Y );
			double angle = radian * (180.0/Math.PI);

			return 90 - angle ;
		}

		public PointF GetRotatingPoint()
		{
			if( _rotationLocked ) return _rotationPointLocked;
			return RectangleUtil.CenterPoint( this.BasePath.GetBounds() ); 
		}

		
		#endregion Rotation/Angle Methods

		#region Path Bounds
//		public RectangleF GetBasePathBounds(Matrix matrix, Pen pen)
//		{
//			if( pen == null) return GetBasePathBounds(matrix);
//			if( matrix == null) return this.BasePath.GetBounds(new Matrix(), pen);
//			return this.BasePath.GetBounds(matrix, pen);
//		}
		public RectangleF GetBasePathBounds(Matrix matrix)
		{
            if (this.BasePath == null) return RectangleF.Empty;
            
            if (matrix == null) return this.BasePath.GetBounds();
			return this.BasePath.GetBounds(matrix);
		}

		public RectangleF GetBasePathBounds()
		{
            if (this.BasePath == null) return RectangleF.Empty;

			return this.BasePath.GetBounds();
		}

		public RectangleF GetPathBounds()
		{
            if (this.Path == null) return RectangleF.Empty;
            
            return this.Path.GetBounds();
		}

		public RectangleF GetPathBounds( Matrix matrix)
		{
            if (this.Path == null) return RectangleF.Empty;

			if( matrix == null)  return this.Path.GetBounds();
			return this.Path.GetBounds(matrix);
		}

		public RectangleF GetPathBounds( Matrix matrix , Pen pen )
		{

            if (pen == null) return this.GetPathBounds(matrix);

            if (this.Path == null) return RectangleF.Empty;

			if( matrix == null)  return this.Path.GetBounds(new Matrix(), pen);

            return this.Path.GetBounds(matrix, pen);

		}

		#endregion Path Bounds

		#region Properties

		protected internal virtual QuickWarper ParentWarper
		{
			get{ return _parentWarper;}
			set{_parentWarper = value;}
		}


		internal Matrix Matrix 
		{
			get
			{
				return _matrix;
			}
		}


		[Category("Transformation")]
		[DefaultValue(typeof(Scale),"Empty")]
		public Scale Scale
		{
			get
			{
				if( !this.CanScale) return Scale.Empty;

				return _scale;
			}
			set
			{
				if(!_canScale) return;

				if(_scale.Equals( value )) return;

				Scale oldValue = _scale;

				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
				try	{		_internalSuspended = true;		OnScaleChanging(e);		}
				finally	{	_internalSuspended = false;	}
				if( e.Cancel ) return;

				_scale = value;

				ResetPath(false);
				OnScaleChanged( new ValueChangeEventArgs( oldValue, value ));

			}
		}


		public void AddScale( int dx, int dy)
		{
			if( !_canScale) return;
			if( dx == 0 && dy == 0) return;

			Scale scale = _scale;
			scale.X += dx;
			scale.Y += dy;
			this.Scale = scale;
		}


		[Category("Transformation")]
		[DefaultValue(0)]
		public int Rotation
		{
			get
			{
				if( !this.CanRotate) return 0;
				
				return _rotation;
			}
			set
			{
				if( !_canRotate ) return;

				if( value == _rotation) return;

				int oldValue = _rotation;
				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
				try	{		_internalSuspended = true;	OnRotationChanging(e);	}
				finally	{	_internalSuspended = false; }
				if( e.Cancel ) return;

				_rotation = value;

				ResetPath(false);
				OnRotationChanged( new ValueChangeEventArgs( oldValue, value ));
			}
		}

		
		public int AddRotation( int angleOffset , PointF rotationAnchor )
		{
			if( !_canRotate ) return _rotation;
			if( angleOffset == 0) return _rotation;

			//------------------------------------------------
			int oldRotation = _rotation;
			ValueChangingEventArgs e = new ValueChangingEventArgs(oldRotation, _rotation + angleOffset );
			try	{		_internalSuspended = true;	OnRotationChanging(e);	}
			finally	{	_internalSuspended = false; }
			if( e.Cancel ) return _rotation;
			//-----------------------------------------------


			_rotation += angleOffset;	

			PointF center			= RectangleUtil.CenterPoint(this.BasePath.GetBounds());
			if(center != rotationAnchor)
				using(Matrix m = new Matrix())
				{
					RectangleF oldValue = _bounds;
					PointF[] loc = new PointF[]{ center };
					m.RotateAt( angleOffset, rotationAnchor);
					m.TransformPoints(loc);

					PointF p2 = loc[0];
					float px = p2.X - center.X ;
					float py = p2.Y - center.Y;
					p2 = oldValue.Location;
					p2.X += px;
					p2.Y += py;
					oldValue.Location = p2;

					this.Bounds = oldValue;
				}
			else ResetPath(false);

			OnRotationChanged( new ValueChangingEventArgs(oldRotation, _rotation ));

			return _rotation;
		}


		[Category("Transformation")]
		[DefaultValue(typeof(Shear),"Empty")]
		public Shear Shear
		{
			get
			{
				if( !this.CanShear) return Shear.Empty;
				return _shear;
			}
			set
			{
				if( !_canShear) return;

				if( _shear.Equals( value )) return;

				Shear oldValue = _shear;

				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
				try	{		_internalSuspended = true;		OnShearChanging(e);		}
				finally	{	_internalSuspended = false;	}
				if( e.Cancel ) return;

				_shear = value;

				ResetPath(false);
				OnShearChanged( new ValueChangeEventArgs( oldValue, value ));
			}
		}
		


		[Category("Transformation")]
		[DefaultValue(typeof(Warp),"Empty")]
		public virtual Warp Warp
		{
			get
			{ 
				if( !this.CanWarp) return Warp.Empty;
				return _warp;
			}
			set
			{
				try
				{
					if(!_canWarp) return;

					if(_warp.Equals(value)) return;
				
					Warp oldValue = _warp;
					ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
					try	{		_internalSuspended = true;	OnWarpChanging(e);	}
					finally	{	_internalSuspended = false;	}
					if( e.Cancel ) return;

					_warp = value;

					ResetPath(false);
					OnWarpChanged( new ValueChangeEventArgs( oldValue, value ));

				}
				catch( Exception e)
				{
					FileWatcher.WriteLine("Shape::Warp failed"+ e.Message);
				}

			}
		}


		#endregion Properties

		#endregion TRANSFORMATION

		#region Design Time
		private int _shapeIndex = -1;
		[Category("Design")]
		[DesignOnly( true )]
		[Browsable( false )]
		[DefaultValue( -1 )]
		[EditorBrowsable( EditorBrowsableState.Never )]
		public int ShapeIndex // Will go to the .resx file
		{
			get
			{ 
				return _shapeIndex;
			}
			set
			{
				_shapeIndex = value;
			}
		}
		
		#endregion Design Time

		#region ShapeFill, Pen and Blends
		Shade _shade = null;
		[DefaultValue(null)]
		[Category("Style")]
		public Shade Shade
		{
			get{ return _shade;}
			set
			{ 
				if( _shade != null) _shade.InternalChanged -= new EventHandler(base.OnInternalChanged);
				_shade = value;
				if( _shade != null) _shade.InternalChanged += new EventHandler(base.OnInternalChanged);

				InvokeInternalChanged(false);
			}
		}


		ShapeFill _fill = null;
		[DefaultValue(null)]
		[Category("Style")]
		public ShapeFill Fill
		{
			get{ return _fill;}
			set
			{ 
				if( _fill != null) _fill.InternalChanged -= new EventHandler(OnInternalChanged);
				_fill = value;
				if( _fill != null) _fill.InternalChanged += new EventHandler(OnInternalChanged);
				InvokeInternalChanged(false);
			}
		}


		ShapePen _pen = null;
		[DefaultValue(null)]
		[Category("Style")]
		public ShapePen Pen
		{
			get{ return _pen;}
			set
			{ 
				if( _pen != null) _pen.InternalChanged -= new EventHandler(OnInternalChanged);
				_pen = value;
				if( _pen != null) _pen.InternalChanged += new EventHandler(OnInternalChanged);
				InvokeInternalChanged(false);
			}
		}


		//		private bool _foregroundPen = true;
		//		[DefaultValue(true)]
		//		[Category("Style")]
		//		public bool ForegroundPen
		//		{
		//			get{ return _foregroundPen;}
		//			set
		//			{
		//				if( value == _foregroundPen) return;
		//
		//				_foregroundPen = value;
		//				InvokeInternalChanged(false);
		//			}
		//		}


		private bool _transformPen = false;
		[DefaultValue(false)]
		[Category("Style")]
		public bool TransformPen
		{
			get{ return _transformPen;}
			set
			{
				if( value == _transformPen) return;

				_transformPen = value;
				InvokeInternalChanged(false);
			}
		}


		ShapeFill _textFill = null;
		[DefaultValue(null)]
		[Category("Text")]
		public ShapeFill TextFill
		{
			get
			{
				if( _textOnly ) return this.Fill;
				return _textFill;
			}
			set
			{ 
				if( _textOnly) 
				{
					this.Fill = value;
					return;
				}

				if( _textFill != null) _textFill.InternalChanged -= new EventHandler(OnInternalChanged);
				_textFill = value;
				if( _textFill != null) _textFill.InternalChanged += new EventHandler(OnInternalChanged);
				InvokeInternalChanged(false);
			}
		}


		ShapePen _textPen = null;
		[DefaultValue(null)]
		[Category("Text")]
		public ShapePen TextPen
		{
			get
			{ 
				if( _textOnly ) return this.Pen;
				return _textPen;
			}
			set
			{ 
				if( _textOnly) 
				{
					this.Pen = value;
					return;
				}

				if( _textPen != null) _textPen.InternalChanged -= new EventHandler(OnInternalChanged);
				_textPen = value;
				if( _textPen != null) _textPen.InternalChanged += new EventHandler(OnInternalChanged);
				InvokeInternalChanged(false);

			}
		}

		//		private bool _foregroundTextPen = true;
		//		[DefaultValue(true)]
		//		[Category("Text")]
		//		public bool ForegroundTextPen
		//		{
		//			get{ return _foregroundTextPen;}
		//			set
		//			{
		//				if( value == _foregroundTextPen) return;
		//
		//				_foregroundTextPen = value;
		//				InvokeInternalChanged(false);
		//			}
		//		}

		private bool _transformTextPen = false;
		[DefaultValue(false)]
		[Category("Text")]
		public bool TransformTextPen
		{
			get
			{ 
				if( _textOnly ) return this.TransformPen;
				return _transformTextPen;
			}
			set
			{
				if( _textOnly) 
				{
					this.TransformPen = value;
					return;
				}

				if( value == _transformTextPen) return;

				_transformTextPen = value;
				InvokeInternalChanged(false);
			}
		}


		Shade _textShade = null;
		[DefaultValue(null)]
		[Category("Text")]
		public Shade TextShade
		{
			get
			{ 
				if( _textOnly ) return this.Shade;
				return _textShade;
			}
			set
			{ 

				if( _textOnly) 
				{
					this.Shade = value;
					return;
				}

				if( _textShade != null) _textShade.InternalChanged -= new EventHandler(OnInternalChanged);
				_textShade = value;
				if( _textShade != null) _textShade.InternalChanged += new EventHandler(OnInternalChanged);
				InvokeInternalChanged(false);
			}
		}


		protected virtual void OnOutlineChanged( object sender, EventArgs e)
		{ 
			this.ResetPath( true );
		}


		Outline _outline = null;
		[DefaultValue(null)]
		[Category("Style")]
		[RefreshProperties( RefreshProperties.All)]
		public virtual Outline Outline
		{
			get
			{
				if( !_canOutline) return null;
				else return _outline; 
			}
			set
			{ 
				if( !_canOutline) throw new InvalidOperationException("This shape can not be outlined");

				if( _outline != null) _outline.InternalChanged -= new EventHandler(OnOutlineChanged);
				_outline = value;
				if( _outline != null) _outline.InternalChanged += new EventHandler(OnOutlineChanged);

				ResetPath( true );
			}
		}


		#endregion ShapeFill and Pen

		#region POINTS
		private PointF[] _controlPoints		= null;
		[Browsable(false)]
		[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden)]
		public virtual PointF[] ControlPoints
		{
			get
			{
				if(_controlPoints != null) return _controlPoints.Clone() as PointF[];
				return null;
			}
			set
			{
				_controlPoints = value;
				//TODO: Control points changed event missing!!!!
			
			}
		}


		#endregion POINTS

		#region SAVE

		#region JPEG Quality sample code
		
		//		private ImageCodecInfo GetEncoderInfo(ImageFormat imageFormat)
		//		{
		//			//If you need a Quality factor while saving a bitmap in SaveBitmap methods
		//			//------------------------------------------------------------------------------------------
		//			//Only jpegs support quality....!!!!
		//			//Gifs need royaltee fee.Sooo...We do not support it then...:)
		//			//			long quality = 100L;
		//			//			Encoder encoder = Encoder.Quality;
		//			//			ImageCodecInfo ici = GetEncoderInfo( format );
		//			//			EncoderParameter param = new EncoderParameter( encoder, quality);//25%quality
		//			//			EncoderParameters encParams = new EncoderParameters(1);
		//			//			encParams.Param[0] = param;
		//			//			bmp.Save(fileName, ici, encParams);
		//			//-------------------------------------------------------------------------------------------
		//
		//			/*
		//				Available formats
		//				Format=BMP
		//				MimeType =image/bmp
		//				Format=JPEG
		//				MimeType =image/jpeg
		//				Format=GIF
		//				MimeType =image/gif
		//				Format=TIFF
		//				MimeType =image/tiff
		//				Format=PNG
		//				MimeType =image/png
		//			*/
		//			string format;
		//			if( imageFormat == ImageFormat.Bmp)  format = "BMP";
		//			else if( imageFormat == ImageFormat.Jpeg)  format = "JPEG";
		//			else if( imageFormat == ImageFormat.Gif)  format = "GIF";
		//			else if( imageFormat == ImageFormat.Tiff)  format = "TIFF";
		//			else if( imageFormat == ImageFormat.Png)  format = "PNG";
		//			else return null;
		//
		//
		//			ImageCodecInfo[] encoders;
		//			encoders = ImageCodecInfo.GetImageEncoders();
		//			for(int j = 0; j < encoders.Length; ++j)
		//				if( encoders[j].FormatDescription == format) return encoders[j];
		//
		//			return null;
		//		}
		//		

		#endregion JPEG Quality

		public Bitmap GetBitmap(  )
		{
			return GetBitmap( Brushes.White );
		}

		public virtual Bitmap GetBitmap( Brush backGroundBrush )
		{
			//Get the visible bounds of the shapes to be painted. 
			//InvalidatingBounds property returns the union of painting bounds of all shapes
			Rectangle picBounds = Rectangle.Ceiling( this.InvalidatingBounds );
			picBounds.Width++;
			picBounds.Height++;

			//Create a bitmap to paint and create a Graphics object based on the image
			Bitmap bmp = new Bitmap( picBounds.Width, picBounds.Height);

			//Paint image
			using(Graphics g = Graphics.FromImage( bmp ))
			{
				//Fill the background outside 
				//of the shape's clipping region,which can also be visible 
				g.FillRectangle( backGroundBrush, Rectangle.FromLTRB(0,0,picBounds.Width, picBounds.Height) );

				//Translate the painting region to image bounds
				int dx = 0;
				int dy = 0;
				dx = picBounds.X <= 0 ? 0: -picBounds.X;
				dy = picBounds.Y <= 0 ? 0: -picBounds.Y;
				g.TranslateTransform( dx, dy, MatrixOrder.Append);

				this.Paint( g );

				return bmp;
			}
		}


		public void SaveAsPicture( string fileName, Brush backGroundBrush )
		{

			using( Bitmap bmp = GetBitmap(backGroundBrush))
			{
				string ext = System.IO.Path.GetExtension(fileName);
			
				//Default image format is bitmap
				ImageFormat format = ImageFormat.Bmp;

				//Otherwise select the image format
				if( string.Compare( ext, ".png", true) == 0)		format = ImageFormat.Png;
				else if( string.Compare( ext, ".jpeg", true) == 0)	format = ImageFormat.Jpeg;
				else if( string.Compare( ext, ".tiff", true) == 0)	format = ImageFormat.Tiff;
				else if( string.Compare( ext, ".gif", true) == 0)	format = ImageFormat.Gif;


				bmp.Save( fileName,  format);
			}
		}


		public void SaveAsPicture( string fileName )
		{
			SaveAsPicture( fileName, Brushes.White );
		}

		#endregion SAVE

		#region REGION PROPERTIES

		private bool _parentExclude = false;

		[Category("Combine")]
		[RefreshProperties( RefreshProperties.All)]
		[DefaultValue(false)]
		public virtual bool ParentExclude
		{
			get
			{
				return _parentExclude;
			}
			set
			{
				
				if( _parentExclude == value) return;
				_parentExclude = value;


				// Check other joins in the container and reset them
				
				if( value)
				{
					if( this.Parent != null )
						foreach( Shape shape in this.Parent.Shapes ) 
						{
							ShapeCombine shapeJoin = shape.Combine;
							if(shapeJoin.Shape == this  ) shape.Combine = ShapeCombine.Empty;
						}

				
					if( !_combine.IsEmpty && _combine.Shape != null && _combine.Shape.JoinedTo != null )
					{
						_combine.Shape.JoinedTo = null;
						_combine.Shape.InvokeInternalChanged( false );
						_combine = ShapeCombine.Empty;
					}
				}

				InvokeInternalChanged( false );

				OnParentExcluded( new EventArgs());

			}
		}

		[Category("Combine")]
		[DefaultValue(typeof(ShapeCombine),"Empty")]
		public virtual ShapeCombine Combine
		{
			get{ return _combine;}
			set
			{ 
				if(_combine.Equals(value)) return;

				VerifyJoin( value );

				ShapeCombineMode mode	= value.Mode;
				Shape join		= value.Shape; 

				if(_combine.Equals(value)) return;

				ShapeCombine oldValue = _combine;
				ValueChangingEventArgs e = new ValueChangingEventArgs(oldValue, value );
				try	{		_internalSuspended = true;	OnJoinChanging(e);	}
				finally	{	_internalSuspended = false;	}
				if( e.Cancel ) return;

				//------------------------------------------------------------------------------------------------------
				// Shape has already been joined, unjoin it!
				if( join !=null && !join.Combine.IsEmpty ) join.Combine = ShapeCombine.Empty;

				if( this.Parent != null && !value.IsEmpty )
				{	// Check other joins in the container and reset them
					foreach( Shape shape in this.Parent.Shapes ) 
					{
						ShapeCombine shapeJoin = shape.Combine;
						if(shapeJoin.Shape == this || shapeJoin.Shape == join ) 
						{
							shape.Combine			= ShapeCombine.Empty;
							shape.ParentExclude		= false;
						}
					}
				}

				Shape oldShape = oldValue.Shape;
				if( oldShape != null  ) oldShape.JoinedTo = null;
				Shape newShape = value.Shape;
				if( newShape != null  ) 
				{
					newShape.JoinedTo		= this;
					newShape.ParentExclude	= false;
				}
				
				_combine = value;

				if( !_combine.IsEmpty ) this.ParentExclude = false;

				OnJoinChanged( new ValueChangeEventArgs( oldValue, _combine ));

				InvokeInternalChanged(false);
			}
		}

		
		void VerifyJoin( ShapeCombine value )
		{
			if( value.Shape == null) return;
			if( this.Parent == null ) return;

			Shape join		= value.Shape;
			ShapeCombineMode mode	= value.Mode;

			//Value is owner?
			if( join == this ) throw new InvalidOperationException("Shape can not be joined to itself");

			// Value is shape container but not parent container?
			if(join is ShapeContainer)
				throw new InvalidOperationException("Shape can not be joined to a Shape Container");
				//throw new InvalidOperationException("Shape can not be joined to another parent container other than its own parent");
					
			//Value is normal child but not in parent container?
			if(  join != null && join.Parent != this.Parent )
					throw new InvalidOperationException("Shape can not be joined to a shape in another container");
		}



		#endregion REGION PROPERTIES 
	
		#region PAINTING

		#region BRUSH
		protected Brush GetBrush( ShapeFill shapeFill , RectangleF bounds, bool isShadeBrush)
		{	
			if( shapeFill == null) return null;

			try
			{
				switch( shapeFill.FillType)
				{
					case FillType.LinearGradient: return ((LinearGradientFill)shapeFill).GetBrush( bounds, _rotation );
					case FillType.PathGradient	: return ((PathGradientFill)shapeFill).GetBrush( bounds );
					case FillType.Hatched		: return this.GetBrush( shapeFill,false , isShadeBrush);
					case FillType.Solid			: return ((SolidFill)shapeFill).GetBrush();
					case FillType.Texture		: return this.GetBrush( shapeFill,false , isShadeBrush);
				}
			}
			catch( Exception e)
			{	FileWatcher.WriteLine("Shape::GetBrush failed.\n"+e.Message +"\n"+ e.StackTrace);	}

			
			return null;
		}

		protected Brush GetBrush( ShapeFill shapeFill, bool isShadeBrush )
		{
			return GetBrush( shapeFill, false , isShadeBrush );
		}

		protected Brush GetBrush( ShapeFill shapeFill , bool text , bool isShadeBrush)
		{//text = true, Brush for text needed
			if( shapeFill == null) return null;
			if( text && _textPath == null) return null;
			if( text && this.JoinedTo != null) return null;


			GraphicsPath path		= text ? _textPath:_path;
			GraphicsPath basePath	= text ? _textBasePath : _basePath;
			RectangleF pb	= path.GetBounds();
			RectangleF bb	= basePath.GetBounds();

			if( pb.Width == 0f || pb.Height == 0f ) return null; 
			if( bb.Width == 0f || bb.Height == 0f ) return null; 

			try
			{
				switch( shapeFill.FillType)
				{
					case FillType.LinearGradient:
					{
						LinearGradientFill fill = (LinearGradientFill)shapeFill;
						if(! _warp.IsEmpty || this.ParentWarper != null || (_outline != null && !_outline.Transform))
							return fill.GetBrush( pb, _rotation );
						else 
							return fill.GetBrush( bb, _matrix );
					}
					case FillType.PathGradient:
					{
						//PathGradient brush should not be transformed, because it doesn't work with
						//Global transformations, because of this
						PathGradientFill fill = (PathGradientFill)shapeFill;
						PathGradientFillMode mode = fill.FillMode;
						if( text && mode == PathGradientFillMode.Default) mode = PathGradientFillMode.Flatten;

						if( mode == PathGradientFillMode.Flatten )
						{
							if( !fill.Tile.IsEmpty) return fill.GetBrush(pb);
							else if(_outline != null && !_outline.Transform) return  fill.GetBrush( pb );//NEW
							else using( GraphicsPath pgPath = new GraphicsPath() )
								 {
									 pgPath.AddRectangle( bb );
									 if( _quickWarper != null) using( GraphicsPath p = _quickWarper.WarpPath( pgPath)) return fill.GetBrush(p);
									 else  if( _matrix != null && !_matrix.IsIdentity)  pgPath.Transform( _matrix );
									 return fill.GetBrush(pgPath);
								 }
						}
						else if( mode == PathGradientFillMode.Elliptic ) 
						{
							if( !fill.Tile.IsEmpty) return fill.GetBrush(pb);
							else if(_outline != null && !_outline.Transform) return  fill.GetBrush( pb );//NEW
							else using( GraphicsPath pgPath = new GraphicsPath() )
								{
									Rectangle r = Rectangle.Ceiling( fill.MakeEllipticBounds( bb ) );
									 r.Inflate( 2,2);
									pgPath.AddEllipse( r );
									if( _quickWarper != null) using( GraphicsPath p = _quickWarper.WarpPath( pgPath)) return fill.GetBrush(p);
									else  if( _matrix != null && !_matrix.IsIdentity)  pgPath.Transform( _matrix );
									return fill.GetBrush(pgPath);
								}
							
								
							
							
							//OLD:return fill.GetBrush( pb );
						}
						else return fill.GetBrush(path);

					}
					case FillType.Hatched	: 
						if( isShadeBrush )  return ((HatchFill)shapeFill).GetPenBrush();
						else return ((HatchFill)shapeFill).GetBrush();
					case FillType.Solid		: return ((SolidFill)shapeFill).GetBrush();
					case FillType.Texture	:
					{
						TextureFill textureFill = (TextureFill)shapeFill;
						TextureBrush textureBrush = textureFill.GetBrush() as TextureBrush;
						
						Matrix m = new Matrix();
			

						if( textureFill.ImageAlign != ImageAlign.None)
						{
							PointF center = RectangleUtil.CenterPoint( bb );
							if( !textureFill.Transform || _matrix == null || _matrix.IsIdentity)
								m.RotateAt(_rotation, center);//Do not rotate when using shape _matrix but translate
							//Do always rotate at the center
							
							PointF pt = center;
							SizeF imageSize = textureFill.ImageSize;
							pt.X-= imageSize.Width/2f;
							pt.Y-= imageSize.Height/2f;

							if( textureFill.ImageAlign == ImageAlign.TopLeft)
							{	pt.X = bb.Left; pt.Y = bb.Top;}

							if( textureFill.ImageWrap != WrapMode.Clamp)
							{
								if( textureFill.ImageAlign == ImageAlign.BottomLeft)
								{	pt.X = bb.Left; pt.Y = bb.Bottom;}

								if( textureFill.ImageAlign == ImageAlign.BottomRight)
								{	pt.X = bb.Right; pt.Y = bb.Bottom;}

								if( textureFill.ImageAlign == ImageAlign.TopRight)
								{	pt.X = bb.Right; pt.Y = bb.Top;}
							}
							else
							{
								if( textureFill.ImageAlign == ImageAlign.BottomLeft)
								{	pt.X = bb.Left; pt.Y = bb.Bottom - imageSize.Height;}

								if( textureFill.ImageAlign == ImageAlign.BottomRight)
								{	pt.X = bb.Right - imageSize.Width; pt.Y = bb.Bottom - imageSize.Height;}

								if( textureFill.ImageAlign == ImageAlign.TopRight)
								{	pt.X = bb.Right - imageSize.Width; pt.Y = bb.Top;}
							}


							m.Translate(pt.X,pt.Y);
						}

						textureBrush.Transform = m;
						
						if( textureFill.Transform) textureBrush.MultiplyTransform( _matrix ,MatrixOrder.Append);
						
						return textureBrush;
					}
				}

			}
			catch( Exception e)
			{
				FileWatcher.WriteLine("Shape::GetBrush failed.\n"+e.Message +"\n"+ e.StackTrace);
			}

			
			return null;


		}


		private Brush GetPenBrush(ShapePen  shapePen, bool transform )
		{ return GetPenBrush( shapePen, transform, false);}

		private Brush GetPenBrush(ShapePen  shapePen, RectangleF bounds,  bool transform )
		{ 
			if( shapePen == null || shapePen.Fill == null) return null;
			if( bounds.Width == 0f && bounds.Height == 0f ) return null; 

			ShapeFill shapeFill = shapePen.Fill;

			try
			{
				switch( shapeFill.FillType)
				{
					case FillType.LinearGradient:
						return ((LinearGradientFill)shapeFill).GetPenBrush( bounds, transform ? _matrix:null,shapePen, _rotation);
					case FillType.PathGradient:
						throw new InvalidOperationException( "PathGradientFill is not supported in ShapePen onjects");
					case FillType.Hatched:return ((HatchFill)shapeFill).GetPenBrush();
						//return this.GetBrush( shapeFill, bounds );
					case FillType.Solid:
						return ((SolidFill)shapeFill).GetBrush();
					case FillType.Texture:
						return this.GetBrush( shapeFill, bounds, true );
				}
			}
			catch( Exception e)
			{	FileWatcher.WriteLine("Shape::GetPenBrush failed.\n" + e.StackTrace);	}

			return null;

		}

		private Brush GetPenBrush(ShapePen  shapePen, bool transform , bool text )
		{
			if( shapePen == null || shapePen.Fill == null) return null;
			if( text && _textPath == null) return null;
			if( text && this.JoinedTo != null ) return null;

			GraphicsPath path		= text ? _textPath:_path;
			GraphicsPath basePath	= text ? _textBasePath : _basePath;
			RectangleF b	= path.GetBounds();
			RectangleF bb	= basePath.GetBounds();

			if( b.Width == 0f && b.Height == 0f ) return null; 
			if( bb.Width == 0f && bb.Height == 0f ) return null; 

			try
			{
				ShapeFill shapeFill = shapePen.Fill;

				switch( shapeFill.FillType)
				{
					case FillType.LinearGradient:

//						if( shapePen.Inset ) return this.GetBrush( shapeFill);//Do not delete this comment...Reserved for future 

						if(!transform) return ((LinearGradientFill)shapeFill).GetPenBrush( path, null, shapePen, _rotation );
						else if(!_warp.IsEmpty || this.ParentWarper != null )
							return ((LinearGradientFill)shapeFill).GetPenBrush( path, _matrix, shapePen, _rotation );
						else return ((LinearGradientFill)shapeFill).GetPenBrush( bb, _matrix , shapePen.Width);
					
					case FillType.PathGradient	: throw new InvalidOperationException( "PathGradientFill is not supported in ShapePen onjects");
					case FillType.Hatched		: return ((HatchFill)shapeFill).GetPenBrush();//return this.GetBrush(shapeFill,text);
					case FillType.Solid			: return ((SolidFill)shapeFill).GetBrush();
					case FillType.Texture		: return this.GetBrush( shapeFill,text, true);
				}

			}
			catch( Exception e)
			{	FileWatcher.WriteLine("Shape::GetPenBrush failed.\n" + e.StackTrace);	}

			return null;
		}

		#endregion BRUSH

		#region PEN
		protected internal Pen GetPen(ShapePen shapePen, bool transform)
		{
			return  GetPen(shapePen, transform, false);
		}

		protected internal Pen GetPen(ShapePen shapePen, RectangleF bounds)
		{
			return GetPen(shapePen, bounds, true);
		}

		protected internal virtual Pen GetPen(ShapePen shapePen, RectangleF bounds, bool transform )
		{	

			if( shapePen == null) return null;

			Pen pen			= null;
			
			try
			{
				if(shapePen.Fill != null)
					using(Brush brush = GetPenBrush( shapePen, bounds,transform) )
					{
						if( brush == null) return null; 
						pen = new Pen( brush);
					}
				else pen = new Pen( shapePen.Color );

				//pen.Alignment		= shapePen.Inset ? PenAlignment.Inset: PenAlignment.Center;//Reserved for future 
				pen.Alignment		= PenAlignment.Center;

				int[] compoundArray = shapePen.Compounds;
				if( compoundArray.Length > 1 ) 
				{
					float[] compounds = new float[compoundArray.Length];
					for (int i = 0; i < compounds .Length; i++) compounds[i] = ((float)compoundArray[i])/100f;
					pen.CompoundArray	= compounds;
				}
				
				pen.DashCap			= shapePen.DashCap;
				pen.DashOffset		= shapePen.DashOffsetGDI;// shapePen.DashOffset;

				if( shapePen.DashStyle == DashStyle.Custom  ) 
				{	
					float[] dashValues = shapePen.DashPatternGDI;// DAshPatternGd ShapePen.ValidateDashPattern( shapePen.DashPattern , shapePen.Width);
					if( dashValues != null ) pen.DashPattern		= dashValues;
					else pen.DashStyle = DashStyle.Solid;
				}
				else pen.DashStyle		= shapePen.DashStyle;

				//pen.EndCap			= shapePen.EndCap;
				pen.LineJoin		= shapePen.LineJoin;
				pen.MiterLimit		= shapePen.MiterLimit;
				//pen.StartCap		= shapePen.StartCap;
				pen.Width			= shapePen.Width;
			

				try		{	if(transform) pen.Transform = _matrix;	}
				catch	{	pen.Width = 1;	}

				shapePen.MakeCap( pen);

				return pen;

			}
			catch( Exception e)
			{
				FileWatcher.WriteLine("Shape::GetPen failed.\n" + e.Message + "\n" + e.StackTrace);
				throw e;
			}
		
		}

		protected internal virtual Pen GetPen(ShapePen shapePen, bool transform, bool text) 
		{	
			if( shapePen == null) return null;
			if( text && this.JoinedTo != null ) return null;
			if( text && _textPath == null) return null;

			Pen pen			= null;
			
			try
			{
				if(shapePen.Fill != null)
					using(Brush brush = GetPenBrush( shapePen, transform, text ))
					{
						if( brush == null) return null; 
						pen = new Pen( brush);
					}
				else pen = new Pen( shapePen.Color );

				//pen.Alignment		= shapePen.Inset ? PenAlignment.Inset: PenAlignment.Center;////Reserved for future
				pen.Alignment		= PenAlignment.Center;

				int[] compoundArray = shapePen.Compounds;
				if( compoundArray.Length > 1 ) 
				{
					float[] compounds = new float[compoundArray.Length];
					for (int i = 0; i < compounds .Length; i++) compounds[i] = ((float)compoundArray[i])/100f;
					pen.CompoundArray	= compounds;
				}
				
				pen.DashCap			= shapePen.DashCap;
				pen.DashOffset		= shapePen.DashOffsetGDI;// shapePen.DashOffset;

				if( shapePen.DashStyle == DashStyle.Custom  ) 
				{	
					float[] dashValues = shapePen.DashPatternGDI;// ShapePen.ValidateDashPattern( shapePen.DashPattern , shapePen.Width);
					if( dashValues != null) pen.DashPattern		= dashValues;
					else pen.DashStyle = DashStyle.Solid;
				}
				else pen.DashStyle		= shapePen.DashStyle;

				//pen.EndCap			= shapePen.EndCap;
				pen.LineJoin		= shapePen.LineJoin;
				pen.MiterLimit		= shapePen.MiterLimit;
				//pen.StartCap		= shapePen.StartCap;
				pen.Width			= shapePen.Width;
			


				try		{	if(transform) pen.Transform = _matrix;	}
				catch	{	pen.Width = 1;	}

				shapePen.MakeCap( pen );


				return pen;

			}
			catch( Exception e)
			{
				FileWatcher.WriteLine("Shape::GetPen failed.\n" + e.Message + "\n" + e.StackTrace);
				throw e;
			}
		
		}

		#endregion PEN

		#region REGION PAINT

		private Brush GetRegionBrush( ShapeFill fill)
		{
			if( fill == null) return null;
			if( _combine.Shape == null) return null;

			GraphicsPath path = _path;
			GraphicsPath join = _combine.Shape._path;

			Brush brush = null;
			if(	(_combine.Mode == ShapeCombineMode.Union) &&
				( fill.FillType == FillType.LinearGradient ||
				( fill.FillType == FillType.PathGradient && ((PathGradientFill)fill).FillMode != PathGradientFillMode.Default)))
			{
				RectangleF b = RectangleF.Union( join.GetBounds(), path.GetBounds());
				brush = GetBrush( fill, b , false);	
			}
			else if( _combine.Mode == ShapeCombineMode.Xor && fill.FillType == FillType.LinearGradient)
			{
				RectangleF b = RectangleF.Union( join.GetBounds(), path.GetBounds());
				brush = GetBrush( fill, b , false);	
			}
			else brush	= GetBrush( fill, false, false );

			return brush;

		}

		private bool FillRegion(Graphics g, ShapeFill fill)
		{
			return FillRegion(g, fill, true);
		}
		private bool FillRegion(Graphics g, ShapeFill fill, bool enableRecursiv )
		{
			if( fill == null) return false;
			if( _combine.Shape == null) return false;

			GraphicsPath path = _path;
			GraphicsPath join = _combine.Shape._path;

			Brush brush = GetRegionBrush(fill);
			if( brush == null) return false;
			

			//Draw backgroundgroundblend first
			if( enableRecursiv ) FillRegion(g, GetBlend(fill, false ), false);

			
			bool isTexture = fill.FillType == FillType.Texture;

			
			switch( _combine.Mode)
			{
				case ShapeCombineMode.Complement:
					g.SetClip( path, CombineMode.Exclude);
					if( isTexture) g.FillPath(brush,join);
					else _combine.Shape.DrawBackground( g, fill,false);
					g.ResetClip();
					break;
				case ShapeCombineMode.Exclude:
					g.SetClip( join, CombineMode.Exclude);
					g.FillPath( brush, path);
					g.ResetClip();
					break;
				case ShapeCombineMode.Intersect:
					g.SetClip( path, CombineMode.Replace);

					if( isTexture) g.FillPath(brush,join);
					else _combine.Shape.DrawBackground( g, fill,false);
					
					g.ResetClip();
					break;
				case ShapeCombineMode.Union:

					if( fill.FillType != FillType.PathGradient)
					{
						using( Region r = new Region( path ))
						{
							r.Xor( join );
							g.FillRegion(brush, r);
						}
						using( Region r = new Region( path ))
						{
							r.Intersect( join );
							g.FillRegion(brush, r);
						}

					}
					else
					{
						PathGradientFill pgf = (PathGradientFill)fill;

						if( pgf.FillMode == PathGradientFillMode.Default)
						{
							bool firstThis = true;
							if( this.Parent != null)
								foreach( Shape shape in this.Parent.Shapes)
								{
									if( shape == this) {firstThis = true; break;}
									if( shape == _combine.Shape) {firstThis = false; break;}
								}

							if( firstThis)
							{
								g.FillPath( brush, path );
								_combine.Shape.DrawBackground(g, fill, false);
							}
							else
							{
								_combine.Shape.DrawBackground(g, fill, false);
								g.FillPath( brush, path );
							}
						}
						else
						{
							using( Region r = new Region( path ))
							{
								r.Xor( join );
								g.FillRegion(brush, r);
							}
							using( Region r = new Region( path ))
							{
								r.Intersect( join );
								g.FillRegion(brush, r);
							}
						}

					}
					
					break;
				case ShapeCombineMode.Xor:
					g.SetClip( path, CombineMode.Exclude);
					if( fill.FillType == FillType.LinearGradient || isTexture)
					{
						g.FillPath(brush,join);
					}
					else _combine.Shape.DrawBackground( g, fill,false);
					
					g.ResetClip();

					g.SetClip( join, CombineMode.Exclude);
					g.FillPath( brush, path);
					g.ResetClip();
					break;
			}


			brush.Dispose(); brush = null;

			//Draw Backg. Blend
			if( enableRecursiv ) FillRegion(g, GetBlend(fill, true ), false);

			return true;
			
		}

		private bool DrawRegion(Graphics g, ShapePen shapePen, bool transform)
		{
			GraphicsPath path		= _path;
			GraphicsPath basePath	= _basePath;
			RectangleF b	= path.GetBounds();
			RectangleF bb	= basePath.GetBounds();

			bool isLine = b.IsEmpty || bb.IsEmpty;// b.Width == 0f || b.Height == 0f || bb.Width == 0f || bb.Height == 0f ;
			Pen pen = GetPen( shapePen, RectangleF.Union( b, _combine.Shape.GetPathBounds()), transform  );
			if( pen == null ) return false;

			Pen joinPen			= pen;

			GraphicsPath join = _combine.Shape._path;
			using( pen)
			switch( _combine.Mode)
			{
				case ShapeCombineMode.Complement:
					g.SetClip( path, CombineMode.Exclude);
					g.DrawPath(joinPen,join);
					g.ResetClip();
					g.SetClip( join, CombineMode.Replace);
					g.DrawPath(pen,path);
					g.ResetClip();
					break;
				case ShapeCombineMode.Exclude:
					g.SetClip( path, CombineMode.Intersect);
					g.DrawPath(joinPen,join);
					g.ResetClip();

					g.SetClip( join, CombineMode.Exclude);
					g.DrawPath(pen,path);
					g.ResetClip();
					break;
				case ShapeCombineMode.Intersect:
					g.SetClip( path, CombineMode.Replace);
					g.DrawPath(joinPen,join);
					g.ResetClip();
					g.SetClip( join, CombineMode.Replace);
					g.DrawPath(pen,path);
					g.ResetClip();
					break;
				case ShapeCombineMode.Union:
					g.SetClip( join, CombineMode.Exclude);
					g.DrawPath(pen,path);
					g.ResetClip();
					g.SetClip( path, CombineMode.Exclude);
					g.DrawPath(joinPen,join);
					g.ResetClip();

					break;
				case ShapeCombineMode.Xor:
					g.DrawPath(pen,join);
					g.DrawPath(pen,path);
					break;
			}//End switch

			return true;
		}

		private bool PaintRegionShade(Graphics g )
		{
			Shade shadow = _shade;
			bool transform = _transformPen;


			if( shadow == null || (shadow.Pen == null && shadow.Fill == null) ) return false;

			GraphicsPath path		= _path;
			RectangleF b	= path.GetBounds();
			RectangleF bb   = _basePath.GetBounds();
			bool isLine = b.IsEmpty || bb.IsEmpty;

			try
			{
				PointF offset = shadow.Offset;
				int repeat = shadow.Repeat;
				if( offset.IsEmpty || repeat == 0 ) return false;

				GraphicsPath join = _combine.Shape._path;

				bool deepShadow = false;// We might make this optional in some cases
				GraphicsContainer shadowContainer = null;
				if( !deepShadow ) 
				{
					Region r = null;

					switch( _combine.Mode)
					{
						case ShapeCombineMode.Complement:
						{
							r = new Region( join );
							r.Exclude( path );
							g.SetClip( r, CombineMode.Exclude);
							break;
						}
						case ShapeCombineMode.Exclude:
						{
							r = new Region( path );
							r.Exclude( join );
							g.SetClip( r, CombineMode.Exclude);
							break;
						}
						case ShapeCombineMode.Intersect:
						{
							r = new Region( path );
							r.Intersect( join );
							g.SetClip( r, CombineMode.Exclude);
							break;
						}
						case ShapeCombineMode.Union:
						{
							r = new Region( path );
							r.Union( join );
							g.SetClip( r, CombineMode.Exclude);
							break;


						}
						case ShapeCombineMode.Xor:
						{
							r = new Region( path );
							r.Xor( join );
							g.SetClip( r, CombineMode.Exclude);
							break;
						}
					}

					if( r != null) r.Dispose(); r = null;

					shadowContainer = g.BeginContainer();
					g.SmoothingMode = SmoothingMode.AntiAlias;
				}


				g.TranslateTransform(repeat * offset.X,repeat * offset.Y,MatrixOrder.Append);

				Brush brush = null;


				ShapeFill fill = null;
				bool isHatch = false;
				if( !isLine )
				{
					fill = shadow.Fill;
					if( fill != null) brush	= GetBrush( fill, false, true);
				}

				using(Pen pen = GetPen( shadow.Pen, transform , false ))
				using(Pen joinPen = _combine.Shape.GetPen( shadow.Pen, transform, false))
				{
					using( brush)
						for( int i= 0; i < repeat; i++) 
						{ 
							switch( _combine.Mode)
							{
								case ShapeCombineMode.Complement:
								{
									//DRAW
									if( pen != null && !shadow.Pen.ForegroundPen)
									{
										g.SetClip( path, CombineMode.Exclude);
										g.DrawPath(joinPen,join);
										g.ResetClip();
										g.SetClip( join, CombineMode.Replace);
										g.DrawPath(pen,path);
										g.ResetClip();
									}
									//PAINT
									if( fill != null )
									{
										g.SetClip( path, CombineMode.Exclude);
										if( isHatch) g.FillPath(brush,join);	
										else _combine.Shape.DrawBackground( g, fill,false);
										g.ResetClip();
									}
									//DRAW
									if( pen != null && shadow.Pen.ForegroundPen)
									{
										g.SetClip( path, CombineMode.Exclude);
										g.DrawPath(joinPen,join);
										g.ResetClip();
										g.SetClip( join, CombineMode.Replace);
										g.DrawPath(pen,path);
										g.ResetClip();
									}

									break;
								}
								case ShapeCombineMode.Exclude:
								{
									if( pen != null && !shadow.Pen.ForegroundPen)
									{
										g.SetClip( path, CombineMode.Intersect);
										g.DrawPath(joinPen,join);
										g.ResetClip();
										g.SetClip( join, CombineMode.Exclude);
										g.DrawPath(pen,path);
										g.ResetClip();
									}

									if( fill != null)
									{
										g.SetClip( join, CombineMode.Exclude);
										g.FillPath( brush, path);
										g.ResetClip();

									}
									if( pen != null && shadow.Pen.ForegroundPen)
									{
										g.SetClip( path, CombineMode.Intersect);
										g.DrawPath(joinPen,join);
										g.ResetClip();
										g.SetClip( join, CombineMode.Exclude);
										g.DrawPath(pen,path);
										g.ResetClip();
									}
									break;
								}
								case ShapeCombineMode.Intersect:
								{
									if( pen != null && !shadow.Pen.ForegroundPen)
									{
										g.SetClip( path, CombineMode.Replace);
										g.DrawPath(joinPen,join);
										g.ResetClip();
										g.SetClip( join, CombineMode.Replace);
										g.DrawPath(pen,path);
										g.ResetClip();
									}

									if( fill != null)
									{
										g.SetClip( path, CombineMode.Replace);
										if( isHatch) g.FillPath(brush,join);
										else _combine.Shape.DrawBackground( g, fill,false);
										g.ResetClip();
									}
									
									if( pen != null && shadow.Pen.ForegroundPen)
									{
										g.SetClip( path, CombineMode.Replace);
										g.DrawPath(joinPen,join);
										g.ResetClip();
										g.SetClip( join, CombineMode.Replace);
										g.DrawPath(pen,path);
										g.ResetClip();
									}
									break;
								}
								case ShapeCombineMode.Union:
								{
									if( pen != null && !shadow.Pen.ForegroundPen)
									{
										g.SetClip( join, CombineMode.Exclude);
										g.DrawPath(pen,path);
										g.ResetClip();
										g.SetClip( path, CombineMode.Exclude);
										g.DrawPath(joinPen,join);
										g.ResetClip();
									}
									if( fill != null)
									{
										using(Region reg = new Region())
										{
											reg.Exclude( join );
											reg.Exclude( path );
											using( Region rg = new Region()) 
											reg.Complement( rg );

											if( fill.FillType == FillType.LinearGradient ||
											( fill.FillType == FillType.PathGradient && ((PathGradientFill)fill).FillMode != PathGradientFillMode.Default))
											{
												RectangleF bx = reg.GetBounds(g);// RectangleF.Union( join.GetBounds(), path.GetBounds());
												using(Brush brushX = GetBrush( fill, bx, true ))
												g.FillRegion( brushX, reg );
											} 
											else 
												g.FillRegion( brush, reg );
										}

									}

									if( pen != null && shadow.Pen.ForegroundPen)
									{
										g.SetClip( join, CombineMode.Exclude);
										g.DrawPath(pen,path);
										g.ResetClip();
										g.SetClip( path, CombineMode.Exclude);
										g.DrawPath(joinPen,join);
										g.ResetClip();
									}

									break;
								}
								case ShapeCombineMode.Xor:
								{
									if( pen != null && !shadow.Pen.ForegroundPen)
									{
										g.DrawPath(pen,join);
										g.DrawPath(pen,path);
									}

									if( fill != null)
									{
										g.SetClip( path, CombineMode.Exclude);
										//if( tb != null) {	g.FillPath( tb, join); g.FillPath(brush,join);	}
										//else _combine.Shape.DrawBackground( g, fill,false);
										if( isHatch ) g.FillPath(brush,join);
										else _combine.Shape.DrawBackground( g, fill,false);
										g.ResetClip();

										g.SetClip( join, CombineMode.Exclude);
										//if( tb != null) g.FillPath( tb, path);
										g.FillPath( brush, path);
										g.ResetClip();

									}

									if( pen != null && shadow.Pen.ForegroundPen)
									{
										g.DrawPath(pen,join);
										g.DrawPath(pen,path);
									}

									break;
								}
							}//End switch

							g.TranslateTransform(-offset.X,-offset.Y,MatrixOrder.Append);

							
					}


					if( shadowContainer != null)
					{
						g.EndContainer( shadowContainer);
						g.ResetClip();
					}


				}
			}
			catch( Exception e)
			{
				FileWatcher.WriteLine( e.StackTrace );
				throw e;
			}


			return true;
		}

		#endregion REGION PAINT

		#region SHADOW

		internal void DrawShade( 
			Graphics g, 
			GraphicsPath path,
			Point offset, 
			int repeat, 
			Brush brush,
			Pen pen,
			bool foregroundPen, 
			bool clip)
		{
			if( path == null || (brush == null && pen == null) || offset.IsEmpty  || repeat == 0) return;
			RectangleF b	= path.GetBounds();
			bool isLine = b.IsEmpty;//  b.Width == 0f || b.Height == 0f;

			GraphicsContainer c = g.BeginContainer();
			g.SmoothingMode = SmoothingMode.AntiAlias;
			if( clip ) g.SetClip( path, CombineMode.Exclude);

			g.TranslateTransform(repeat * offset.X,repeat * offset.Y,MatrixOrder.Append);

			if( isLine)
			{
				for( int i= 0; i < repeat; i++) 
				{ 
					//g.DrawLine(pen,path.PathPoints[0],path.GetLastPoint());
					g.DrawPath( pen,path );
					g.TranslateTransform(-offset.X,-offset.Y,MatrixOrder.Append);
				} 
			}
			else
			{

					for( int i= 0; i < repeat; i++) 
					{
						if( pen != null && !foregroundPen) g.DrawPath( pen,path );
						if( brush != null) g.FillPath( brush, path);
						if( pen != null && foregroundPen) g.DrawPath( pen,path );

						g.TranslateTransform(-offset.X,-offset.Y,MatrixOrder.Append);

					}
			}

			if( clip ) g.SetClip( path, CombineMode.Union);

			g.EndContainer(c );
		}


		protected void DrawShade( Graphics g, bool text )
		{
			Shade shade  = text ? _textShade:_shade;
			if( shade == null) return;
			if( shade.Fill == null && shade.Pen == null) return;
			if( text && _textPath == null) return;
			
			GraphicsPath path		= text ? _textPath:_path;
			if( path == null) return;
			RectangleF b	= path.GetBounds();

			bool isLine = b.IsEmpty;// b.Width == 0f || b.Height == 0f  ;
			if( text && isLine) return;

			if( shade.Offset.IsEmpty || shade.Repeat <= 0 ) return;

			Pen shadePen = shade.Pen == null? null:GetPen( shade.Pen, _transformPen , text);

			Brush shadeBrush = null;

			if( isLine ) shadeBrush = null;
			else if( shade.Fill != null) 
				shadeBrush  = GetBrush( shade.Fill, text, true);
			

			if( !text ) g.SetClip( path, CombineMode.Exclude);

			int repeat = shade.Repeat;
			Point offset = shade.Offset;
		
			g.TranslateTransform(repeat * offset.X,repeat * offset.Y,MatrixOrder.Append);

			using( shadeBrush )
			using( shadePen )
				for( int i= 0; i < repeat; i++) 
				{ 
					if( shadePen != null && !shade.Pen.ForegroundPen)
					{
						if( isLine ) g.DrawLine(shadePen,path.PathPoints[0],path.GetLastPoint()); 
						else g.DrawPath( shadePen,path ); 
					}

					if( shadeBrush != null )
					{
						g.FillPath( shadeBrush, path);
					}

					if( shadePen != null && shade.Pen.ForegroundPen)
					{
						if( isLine ) g.DrawLine(shadePen,path.PathPoints[0],path.GetLastPoint()); 
						else g.DrawPath( shadePen,path ); 
					}

					if( shadePen == null && shadeBrush == null && this.DesignMode ) DrawInvisible(g, path);

					g.TranslateTransform(-offset.X,-offset.Y,MatrixOrder.Append);
				} 


			
			if( !text ) g.SetClip( path, CombineMode.Union);

		}



		#endregion SHADOW

		#region NON-REGION PAINTING

		private ShapeFill GetBlend(ShapeFill fill, bool foreground)
		{
			if( fill == null) return null;
			if( fill.FillType == FillType.None ) return null;

 
			IMultiBrushFill blend = fill as IMultiBrushFill;

			if( blend == null) return null;

			if( blend.ForegroundBlend != foreground ) return null;
			return blend.Blend;			
		}
		
		private Brush GetBlendBrush( ShapeFill fill, bool foreground, bool text )
		{
			ShapeFill blend = GetBlend( fill, foreground );

			if( blend == null) return null;

			return GetBrush( blend, text , false);
		}
		

		protected bool DrawBackground(Graphics g, ShapeFill fill, bool text)
		{
			if( text && _textPath == null) return false;
			if( text && this.JoinedTo != null) return false;

			Brush brush	= GetBrush( fill, text , false);
			if( brush == null) return false;
			
			using( brush )
			{
				GraphicsPath path = text ? _textPath: _path;
				using(Brush backgBlend = GetBlendBrush( fill,false, text )) 
					if( backgBlend != null) g.FillPath( backgBlend, path);

				g.FillPath( brush, path);

				using(Brush foregBlend = GetBlendBrush( fill,true, text )) 
					if( foregBlend != null) g.FillPath( foregBlend, path);


			}
			
			return true;
		}

		protected bool DrawBorder(Graphics g, ShapePen shapePen, bool transform, bool text)
		{
			if( text && _textPath == null) return false;
			if( text && this.JoinedTo != null) return false;

			Pen pen				= GetPen( shapePen, transform, text );
			if( pen == null ) return false;

			using( pen)
			{
				GraphicsPath path		= text ? _textPath:_path;
				GraphicsPath basePath	= text ? _textBasePath : _basePath;
				RectangleF b	= path.GetBounds();
				RectangleF bb	= basePath.GetBounds();

				bool isLine = b.Width == 0f || b.Height == 0f || bb.Width == 0f || bb.Height == 0f ;

				if( isLine ) g.DrawLine(pen,path.PathPoints[0],path.GetLastPoint()); 
				else g.DrawPath(pen,path); 
		
			}
				
			return true;
		}

		protected virtual void DrawInvisible(Graphics g, GraphicsPath path )
		{
			//TODO: To be added again.. But should not paint when saving as picture
//			g.DrawPath( SystemPens.ControlLight, path );
		}

		
		#endregion PAINTING
	

		public virtual void Paint( Graphics g )
		{
			if( this.BasePath/* _basePath */ == null) return;//Force to make path

			if(_parentExclude || _suspended || _internalSuspended )	return;
			if( !this.Visible && !this.DesignMode )	return;	
			if( this.JoinedTo != null )	return;	
			
			if( _textPath != null) _textPath.FillMode = FillMode.Winding;

			_path.FillMode = _fillMode;

			Shape join = _combine.Shape;

			GraphicsContainer container = g.BeginContainer();
			g.SmoothingMode = SmoothingMode.AntiAlias;

			
			try
			{
				//Draw Invisible blend
				//if( !this.Visible  ){	DrawInvisible(g);return;	}

				if( this.DesignMode && 
					join != null&&
					_combine.Mode != ShapeCombineMode.Union &&
					_combine.Mode != ShapeCombineMode.Xor)
				{	this.DrawInvisible( g, _path );join.DrawInvisible( g, _path ); }

				bool		penOK	= false;
				bool		brushOK	= false;

				//--------------------------------------------------------------------------------------------------------------
				//Draw Shade
				//--------------------------------------------------------------------------------------------------------------
				if( _shade != null)
				{
					if( join == null)
					{

						DrawShade( g, false);
					}
					else
					{
						PaintRegionShade( g );
					}

				}
				//--------------------------------------------------------------------------------------------------------------
				//Draw Background and border
				//--------------------------------------------------------------------------------------------------------------
				penOK	= false;
				brushOK	= false;
				if( join != null)
				{
					if( _pen != null && !_pen.ForegroundPen) penOK = DrawRegion(g, _pen, _transformPen);
					brushOK	= FillRegion(g, _fill );
					if( _pen != null && _pen.ForegroundPen) penOK = DrawRegion(g, _pen, _transformPen);
					//if( !penOK && !brushOK && this.DesignMode ) DrawInvisible(g);
				}
				else
				{
					if( _pen != null && !_pen.ForegroundPen) penOK = DrawBorder(g, _pen, _transformPen, false);
					brushOK	= DrawBackground(g, _fill , false );
					if( _pen != null && _pen.ForegroundPen) penOK  = DrawBorder(g, _pen, _transformPen, false);
					if( !penOK && !brushOK && this.DesignMode ) DrawInvisible(g, _path);
				}

				//---------------------------------------------- TEXT ----------------------------------------------------------
				if(_textPath == null) return;
				//Draw Text Shade
				//--------------------------------------------------------------------------------------------------------------
				if( _textShade != null )
				{
					g.SetClip( _textPath, CombineMode.Exclude );
					DrawShade( g, true );
					g.SetClip( _textPath, CombineMode.Union );
				}

				//--------------------------------------------------------------------------------------------------------------
				//Draw TEXT Background and border
				//--------------------------------------------------------------------------------------------------------------
				if( _textPen != null && !_textPen.ForegroundPen) DrawBorder(g, _textPen, _transformTextPen, true);
				DrawBackground(g, _textFill , true );
				if( _textPen != null && _textPen.ForegroundPen) DrawBorder(g, _textPen, _transformTextPen, true);

			}
			catch(Exception e )
			{
				g.ResetClip();
				g.FillPath( Brushes.Black, _basePath);
				g.DrawString( e.Message,new Font("Tahoma", 10),Brushes.White,_basePath.GetBounds());
			}
			finally
			{
				g.EndContainer(container);
			}
		}
		

		#endregion PAINTING


	}



}
